The other day I started to think about why do you need
to use mov/pop etc. to fill that structure? couldnt it just be
predefined? or will it just have no advantage at all?

Needless to say that you would still need to fill some
values with calls like 'LoadIcon/LoadCursor' etc.

Example code,
WNDCLASSEX <sizeof WNDCLASSEX,\

CS_HREDRAW or CS_VREDRAW,\
offset WndProc,0,0,\
400000h,0,0,\
COLOR_WINDOW+1,0,\
offset szClassName,0>
Posted on 2002-12-03 13:32:18 by natas
That looks like my code :grin:

http://www.asmcommunity.net/board/index.php?topic=6645&highlight=WNDCLASSEX

The only advantage is that you dont need all that mov/push/pop stuff :) The WNDCLASSEX contains fixed data anyway, so why should you add it dynamic then? :)
Posted on 2002-12-03 13:35:25 by bazik
Bazik, What? trust me when I say that I have never seen
that thread before(seriously, but what a coincidence.) So then
there is an advantage. Since it produces less code it's way
better. Thanks for confirming what i believed to be correct. :alright:
Posted on 2002-12-03 13:41:04 by natas
JFYI: I use WNDCLASSEX that way since The Svin posted this method in the old assembly forum (also the 400000h thing) and never had any problems :)
Posted on 2002-12-03 14:05:23 by bazik
After I started to 'really' think about my question. I know believe
it was a pretty dumb thing to ask. Since all the code does is to define
variables inside the structure. Wich should be no different from defining
something like: 'szDoobie DB "MyDoobie",0'. Oh well..
:stupid:

Anyway, The Svin always have alot of good things to say.
Maybe he could write some optimizations for W32Asm? ( ;) )
Hopefully he reads this and wants to comment.
Posted on 2002-12-03 14:44:37 by natas

After I started to 'really' think about my question. I know believe
it was a pretty dumb thing to ask. Since all the code does is to define
variables inside the structure. Wich should be no different from defining
something like: 'szDoobie DB "MyDoobie",0'. Oh well..
:stupid:


But as I said you dont need to mov/push/pop stuff in the structure and that saves some bytes :grin:
Posted on 2002-12-03 15:01:09 by bazik
Bazik, AGREE? :grin:
Posted on 2002-12-03 15:26:21 by natas
The Svin always have alot of good things to say. Maybe he could write some optimizations for W32Asm?


You need to spend some time on the Algo & Source forum... :grin:
Posted on 2002-12-03 15:52:56 by S/390
Originally posted by S/390
You need to spend some time on the Algo & Source forum... :grin:

Actually I think you're right! ( :) ) I dont spend enough time there. Maybe
the time has come for me to be brave and camp there for a couple of days :grin:
Posted on 2002-12-03 16:01:00 by natas
Predefined structures work fine but you have this problem, it does add to the size of the assembled file as it is in the initialised data section and it still must have runtime derived data added to it at runtime so it reduces the advantage by requiring code to be added to it.

This is fine in tiny test pieces but it is not reusable code so for each window you need to create, you have to add another predefined WNDCLASSEX structure to your initialised data section.

A WNDCLASSEX structure is 48 bytes long and you still have to add code to it at runtime.

96 bytes gives you fully reusable code that does not inflate the .DATA section and handles all of the parameter placement in the WNDCLASSEX in one place. This is why I use the following code.


; ?=?=?=?=?=?=?=?=?=?=?=?=?=?=?=?=?=?=?=?=?=?=?=?=?=?=?=?=?=?=?=?=?=?=?=?=?

RegisterWinClass proc lpWndProc:DWORD, lpClassName:DWORD,
Icon:DWORD, Cursor:DWORD, bColor:DWORD

LOCAL wc:WNDCLASSEX

mov wc.cbSize, sizeof WNDCLASSEX
mov wc.style, CS_BYTEALIGNCLIENT or \
CS_BYTEALIGNWINDOW
m2m wc.lpfnWndProc, lpWndProc
mov wc.cbClsExtra, NULL
mov wc.cbWndExtra, NULL
m2m wc.hInstance, hInstance
m2m wc.hbrBackground, bColor
mov wc.lpszMenuName, NULL
m2m wc.lpszClassName, lpClassName
m2m wc.hIcon, Icon
m2m wc.hCursor, Cursor
m2m wc.hIconSm, Icon

invoke RegisterClassEx, ADDR wc

ret

RegisterWinClass endp

; ?=?=?=?=?=?=?=?=?=?=?=?=?=?=?=?=?=?=?=?=?=?=?=?=?=?=?=?=?=?=?=?=?=?=?=?=?


Regards,

hutch@movsd.com
Posted on 2002-12-03 16:32:59 by hutch--
it is not reusable code so for each window you need to create, you have to add another predefined WNDCLASSEX structure to your initialised data section.


hutch, I don't think this is correct. I've used the same structure to register multiple windows. I'll just change the name, proc address, style, maybe icon, etc. Once you issue registerclass the struture is never referenced again. That's also why you can get away with making it a local.

:)
Posted on 2002-12-03 17:50:43 by S/390
I had a little time to waste this morning so I put the theories to the test. Size results are below.

For identical functionality of a dynamically produced instance handle, both static and dynamic methods are 88 bytes long. Where you can save 10 bytes is if you preset the instance handle at 400000h but this cannot be used in a DLL as it is not known at assembler time.

What removes the advantage of presetting the parameters for the RegisterClassEx function is that some parameters can only be determined at runtime and this means providing the code to overwrite the memory locations in the .DATA section.

In both examples, the shorter code


mov eax, mem
mov othermem, eax

has been used and it is to the advantage of the dynamic code version by a couple of bytes for each instruction pair.

Reuse gives the advantage to the dynamic version as the parameters are written on the stack instead of having to repeatedly overwrite memory locations in the .DATA section. You simply keep a procedure that does the changes you require and pass the number of parameters you need to be changed.



========================================================

48 bytes

wc WNDCLASSEX <sizeof WNDCLASSEX, \
CS_BYTEALIGNCLIENT or CS_BYTEALIGNWINDOW, \
OFFSET WndProc, \
NULL,NULL, \
400000h, \
NULL,NULL,COLOR_BTNFACE+1, \
NULL,OFFSET szClassName,NULL>

40 bytes

mov eax, hInstance
mov wc.hInstance, eax
mov eax, hIcon
mov wc.hIcon, eax
mov eax, hCursor
mov wc.hCursor, eax
mov eax, hIcon
mov wc.hIconSm, eax

004014D3 A170334000 mov eax,[403370h]
004014D8 A335304000 mov [403035h],eax
004014DD A178334000 mov eax,[403378h]
004014E2 A339304000 mov [403039h],eax
004014E7 A17C334000 mov eax,[40337Ch]
004014EC A33D304000 mov [40303Dh],eax
004014F1 A178334000 mov eax,[403378h]
004014F6 A34D304000 mov [40304Dh],eax

Total 88 bytes

========================================================

Total 88 bytes

mov wcx.cbSize, sizeof WNDCLASSEX
mov wcx.style, CS_BYTEALIGNCLIENT or \
CS_BYTEALIGNWINDOW
mov wcx.lpfnWndProc, OFFSET WndProc
mov wcx.cbClsExtra, NULL
mov wcx.cbWndExtra, NULL
mov eax, hInstance
mov wcx.hInstance, eax
mov wcx.hbrBackground, COLOR_BTNFACE+1
mov wcx.lpszMenuName, NULL
mov wcx.lpszClassName, OFFSET szClassName
mov eax, hIcon
mov wcx.hIcon, eax
mov eax, hCursor
mov wcx.hCursor, eax
mov eax, hIcon
mov wcx.hIconSm, eax

004014D3 C745C030000000 mov dword ptr [ebp-40h],30h
004014DA C745C400300000 mov dword ptr [ebp-3Ch],3000h
004014E1 C745C81A164000 mov dword ptr [ebp-38h],40161Ah
004014E8 C745CC00000000 mov dword ptr [ebp-34h],0
004014EF C745D000000000 mov dword ptr [ebp-30h],0
004014F6 A170334000 mov eax,[403370h]
004014FB 8945D4 mov [ebp-2Ch],eax
004014FE C745E010000000 mov dword ptr [ebp-20h],10h
00401505 C745E400000000 mov dword ptr [ebp-1Ch],0
0040150C C745E812304000 mov dword ptr [ebp-18h],403012h
00401513 A178334000 mov eax,[403378h]
00401518 8945D8 mov [ebp-28h],eax
0040151B A17C334000 mov eax,[40337Ch]
00401520 8945DC mov [ebp-24h],eax
00401523 A178334000 mov eax,[403378h]
00401528 8945EC mov [ebp-14h],eax

========================================================

Regards,

hutch@movsd.com
Posted on 2002-12-03 19:23:07 by hutch--
Nice one, hutch-- :)

So for the first call to RegisterClassEx we need 88 bytes either way. What about subsequent calls?

With wc in the .DATA section, it will often be possible to leave the previous settings of wc.hIcon, wc.hIconSm, and wc.hCursor unchanged. Two or three MOV's at any place in the code may suffice to prepare the wc structure for another call to RegisterClassEx.

With wc on the stack, and a dedicated procedure to fill it in, the overhead in other places of the code may be much larger. For example, you posted your RegisterWinClass procedure above:


RegisterWinClass proc lpWndProc:DWORD, lpClassName:DWORD,
Icon:DWORD, Cursor:DWORD, bColor:DWORD


Each call to it requires five PUSHes (for parameter passing) someplace else in the code. The more flexible that procedure, the greater the overhead: Assume we wished to be able to change wc.style with that procedure, too (which it currently does not allow), then six parameter PUSHes would be required. Not only the one time where we actually do want to change wc.style, but each time that we call the procedure. These "hidden costs" may grow much more quickly (in terms of bytes in the .CODE section) than if we used a wc structure in the .DATA section and did a single MOV wc.style, IMM as in the static method.

Regards,

Frank
Posted on 2002-12-03 21:16:46 by Frank
Mine looks like this:


wc WNDCLASSEX <sizeof WNDCLASSEX, \
CS_BYTEALIGNCLIENT or CS_BYTEALIGNWINDOW, \
OFFSET WndProc, \
NULL,NULL, \
400000h, \
NULL,NULL,COLOR_BTNFACE+1, \
NULL,OFFSET szClassName,NULL>

hInstance EQU <wc.hInstance>
hIcon EQU <wc.hIcon>
hCursor EQU <wc.hCursor>
Posted on 2002-12-03 23:45:45 by bitRAKE
Rickey,

I gather that you load the structure members with the return values from the functions that get the icon and cursor handles ?

It is actually a good idea and is very code efficient over using a seperate variable.

Regards,

hutch@movsd.com
Posted on 2002-12-04 03:53:54 by hutch--
Thanks for all the reply's guys. And a special thanks to Hutch
for pointing out some things wich should have been obvious (:o).
Posted on 2002-12-04 08:28:47 by natas
Steve,
difference in size in your example is not because of using
data in .data section or data in local vars.
It just 'cause working with locals you use for addressing ebp
as base that's way addressing need 2 bytes(if offset from
base is in range from - 128 to + 127) instead of 4 when you
specify offset as imm.
You can do the same with data in .data section if you load
address of structure in some reg and then address members
as
Using predefined vars is always shorter and faster code,
it's simple arithmitics:
dinamically loading is data in opcode + opcode to load.
predefind data - just the same data that is in above line but
without opcode.
So you are wrong about size, size of executable is not
just size of data, it is size of code and data.
And part that need to fill structure in code section are always
bigger then sum of predefined data and code you need to fill
members that you can not define in desing time.
Actually you might be right but only if:
1. You don't have .data section at all
2. You exe does almost nothing so that having both
data and code in .code section their size <= file alignment.
In this case if it is not exceed size of alignment it will be shorter
than the same in two section with data predefined.
We are talking of 1 kb exe only.
As I said almost two years ago - give me example of exe with
local structs that you dinamically fill and we'll see if I can
write the same code but with predefined data in .data section
and if I can make it shorter in size.

Also talking of time to access data in data section you
forget of two separate caches for code and data. And both stack and data
section share the same data line chache.

Working with stack is nothing else then working with data that is
pointed by esp reg. Load into esp addresses of vars in .data
section and nothing will change.
And stack and .data section are both data.
Posted on 2002-12-04 11:16:36 by The Svin
Thanks The Svin, at first I thought I had all the answers i
could get. But suddenly out of nowhere you come and enlighten
me even more. I have learned a great deal in this thread, since
the responses made me see some things in a new light. :alright:

Out of the thread: I started reading a book titled:
Windows Assembly & Systems Programming(Second Edition) by Barry Kauler.
Have anyone read this book? or maybe someone knows a better one?
I have just read some chapters, but it looks pretty good sofar.
Posted on 2002-12-04 14:11:06 by natas
Example seems to solve the debate about the virtues of dynamic versus static code. I have attached a 1536 byte EXE file with a working window to make the point. This EXE file has no .DATA section at all.

I have done the pseudo smart VC++ style micro-optimisations and as usual it make no difference in size at all. There has always been more to code size optimisation than nitpicking mnemonics and to prove the point, the example has an equate that excludes a couple of blocks of code in the WndProc which actually make the code larger.

The action in both size and speed optimisation has always been in terms of architecture, not close range nitpicking to remove a byte here and there. The only place I know where this type of coding is practiced to any advantage is with the virus nerds who are overwriting locations in existing EXE files where size is very limited.

Regards,

hutch@movsd.com
Posted on 2002-12-04 18:16:51 by hutch--
I think rather the optimization should be focused more on CreateWindowEx, which has an obscene number of arguments, and many times most of them are constant, or known at compile time.


[size=12].data

cwArgs CREATESTRUCT < NULL, etc... >

.code
CreateWindow2 proc uses ecx, edi esi, lpCreateStruct:dword
mov ecx, sizeof CREATESTRUCT
mov esi, lpCreateStruct
sub esp, ecx
mov edi, esp
rep movsb
call CreateWindowEx
ret
CreateWindow2 endp[/size]


...and then somewhere in your program:

[size=12]   ...

...
invoke CreateWindow2, offset cwArgs
test eax, eax
jz error
mov hWnd, eax
...
...[/size]


...and if you want to create similar windows afterwards, you only need to make minimal, if any, changes to the structure.
Posted on 2002-12-04 19:52:28 by iblis