News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

CreateWindowEx Error

Started by raleeper, August 07, 2011, 04:00:27 AM

Previous topic - Next topic

raleeper

The code below gives the error "Cannot find window class."

Would someone be so kind as to look at it and see if anything stands out as a possible cause.
I apologize for the idiosyncratic programming style.  I think I've included everything relevant.

Thank you, ral

;;   NEWWIN   NEW child WINdow

newwin:
   invoke   RegisterClassEx, OFFSET LFwcc

   or   eax, eax
     jz   germs

   mov   edx, CW_USEDEFAULT

   mov   ecx, [hwnd]

   xor   eax,eax

   mov   esi, OFFSET ChldClass

   mov   edi, OFFSET ChildW

   invoke   CreateWindowEx,eax,esi,edi,chstyle,edx,edx,edx,edx,\
   ecx,0,hinst,eax

   mov   [hcwnd], eax

   or   eax, eax
     jz   germs

   retn

LFwcc   LABEL   DWORD      ;LFile Window Child Class structure
   DD   SIZEOF WNDCLASSEX   ; 0 wc.cbSize
   DD   chstyle             ; 4 CHild style
   DD   OF CWProc          ; 8 Child WPROC
   DD   0,0                          ;0C wc.cbClsExtra, wc.cbWndExtra
   DD   ?                    ;14 wc.hinst
cicon   DD   hicon         ;18 LoadIcon,0,IDI_APPLICATION
   DD   hcurs            ;1C LoadCursor,NULL,IDC_ARROW
   DD   hbkbr            ;20 CreateSolidBrush,0FF0000h
wccmen   DD   0            ;24 wc.lpszMenuName
   DD   OF ChldClass         ;28 wc.lpszClassName
   DD   hiconsm            ;2C wc.hIconS

ChldClass   DB   "LFChildclass",0
ChildW      DB   "lfwChild",0
hcwnd      DD   ?

chstyle      EQU   CS_HREDRAW or CS_VREDRAW or CS_DBLCLK

germs is a routine that calls GetLastError, and FormatMessage and shows the result.

hwnd is the handle to the main window.
hicon, hcurs, hbkgr, and hiconsm are all pointers to values obtained for the main window.

zekyr

hi! I had a question about your code;

   mov   ecx, [hwnd]

is that similar to mov ecx, OFFSET hwnd?

the brackets always confuse me on memory :)

thanks


edit: whoops! we dont need the offset of the handle! thats pointer to pointer isnt it?

shouldnt it be mov ecx, hwnd from http://msdn.microsoft.com/en-us/library/ms632680(v=vs.85).aspx

dedndave

here is an example of how to register a window class...
in the DATA section...
        .DATA
ClassString db 'SomeClassName',0

in the DATA? section...
        .DATA?
hInstance   dd ?
hCursor     dd ?
hIcon       dd ?
wc  WNDCLASSEX <>

that allocates an empty structure and a few handles
the structure is typically filled with code..
        INVOKE  GetModuleHandle,NULL
        mov     hInstance,eax
        INVOKE  LoadCursor,NULL,IDC_ARROW
        mov     hCuror,eax
        INVOKE  LoadIcon,NULL,IDI_APPLICATION
        mov     hIcon,eax                             ;EAX = hIcon

        mov     wc.cbSize,sizeof WNDCLASSEX
        mov     wc.style,CS_HREDRAW or CS_VREDRAW
        mov     wc.lpfnWndProc,WndProc
        mov     wc.cbClsExtra,0
        mov     wc.cbWndExtra,0
        push    hInstance
        pop     wc.hInstance
        mov     wc.hIcon,eax
        push    hCursor
        pop     wc.hCursor
        mov     wc.hbrBackground,COLOR_BTNFACE+1
        mov     wc.lpszMenuName,NULL
        mov     wc.lpszClassName,offset ClassString
        mov     wc.hIconSm,eax
        INVOKE  RegisterClassEx,offset wc


you may test the value of EAX after the call to RegisterClassEx to see if it was successful
if so, you may now reference the registered class by the ClassString
the second parameter of CreateWindowEx is...
offset ClassString

there are a number of variations, but that should get you started

the WNDCLASSEX structure is defined in windows.inc
no need to define it with DD's

you can put the structure in the DATA section and initialize most of the members
        .DATA
wc WNDCLASSEX <sizeof WNDCLASSEX,CS_HREDRAW or CS_VREDRAW,WndProc,0,0,?,?,?,COLOR_BTNFACE+1,NULL,ClassString,?>

then fill in hInstance, hCursor, hIcon, and hIconSm with code

doing it that way is probably smaller than doing it all with code   :bg
that's a good idea, Ral   :U

ixuta

@Zekyr
mov ecx,[hwnd]              ;put contents of address pointed to by hwnd into ecx register  ;or say put contents of memory named/labled hwnd into ecx register
mov ecx,hwnd                 ;put address of hwnd into ecx register

hwnd    ;address of
[hwnd]  ;contents of

//   Like in c
x = *myPtr     ; that is like mov ecx,[hwnd]  ;x gets value pointed to by myPtr
x = myPtr       ; that is like mov ecx, hwnd    ;x gets value of myPtr
...
as for the code, I see one line that says
"""   DD   OF CWProc          ; 8 Child WPROC  """
shouldn't it say
""" DD OFFSET CWProc  """"
unless "OF" is shorthand for OFFSET, or ADDRESS OF,  is it???  I haven't seen "OF" before

raleeper

Quote from: ixuta on August 07, 2011, 05:52:18 AM
...
as for the code, I see one line that says
"""   DD   OF CWProc          ; 8 Child WPROC  """
shouldn't it say
""" DD OFFSET CWProc  """"
unless "OF" is shorthand for OFFSET, or ADDRESS OF,  is it???  I haven't seen "OF" before

Yes.  Sorry.  I forgot to replace 2 occurrences of "OF" in the WNDCLASSEX.  I'm a lazy typist so I have an equate.

raleeper

Quote from: dedndave on August 07, 2011, 05:50:09 AM
here is an example of how to register a window class...
  [snip]

Thanks.  I'm digesting this.

raleeper

@dedndave:

Hmm.  Here's how I do it for my main window, and it works fine.
So far I don't see a difference with your code that could be causing the problem.
RegisterClassEx doesn't return an error - it returns 7ffd0000.  I'll try using that in CreateWindowEx.
Except that I don't understand the SDK help, which says:

QuotelpClassName   [in] Pointer to 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. If lpClassName is a string, it specifies the window class name.



In .DATA

LFwc LABEL DWORD ;LFile Window Class structure
DD SIZEOF WNDCLASSEX ; 0 wc.cbSize
DD lfstyle ; 4 wc.style
DD OFFSET WProc ; 8 wc.lpfnWndProc
DD 0,0 ;0C wc.cbClsExtra, wc.cbWndExtra
hinst DD ? ;14 wc.hinst
hicon DD ? ;18 LoadIcon,0,IDI_APPLICATION
hcurs DD ? ;1C LoadCursor,NULL,IDC_ARROW
hbkbr DD ? ;20 CreateSolidBrush,0FF0000h
wcmen DD 0 ;24 wc.lpszMenuName
DD OFFSET ClassName ;28 wc.lpszClassName
hiconsm DD ? ;2C wc.hIconSm
;30 end LFwc


In .CODE

start:
invoke CreateSolidBrush,0FF0000h
mov [hbkbr], eax

invoke LoadIcon,0,IDI_APPLICATION
mov [hicon], eax
mov [hiconsm], eax

invoke LoadCursor,0,IDC_ARROW
mov [hcurs], eax

invoke GetModuleHandle, 0
mov [hinst], eax

and in winmain

WinMain proc hInst:HINSTANCE, hPrevInst:HINSTANCE, CmdLine:LPSTR, CmdShow:DWORD

LOCAL msg:MSG

invoke RegisterClassEx, OFFSET LFwc

mov edx, CW_USEDEFAULT
xor eax,eax
invoke CreateWindowEx,eax,ADDR ClassName,ADDR AppName,\
WS_OVERLAPPEDWINDOW,edx,edx,edx,edx,eax,eax,hInst,eax

mov [hwnd], eax

zekyr

thought it was like

mov eax, [hwnd]   ;grab memory pointed to by hwnd and stick it into eax
mov eax, hwnd     ;stick handle into eax (which i thought we wanted here)
mov eax, offset hwnd ;stick address of hwnd which has a handle in it, which could be dereferenced into eax

or um

c-example would be like
int * ptr = myptr;
printf("%d %d %d",*ptr , ptr, &ptr);

my apologies for bringing up dumb questions all the time :D

dedndave

Ral,
the code you posted leaves a few things unclear
for example, i do not know what the value of lfstyle is, as you do not show it
as you have shown it being used, it should be an EQUate that represents a set of valid style bits

as for using the global class atom returned in RegisterClassEx as the lpClassName parameter,
that requires that the atom be converted to a 16-bit local atom - more trouble than it's worth

i think the problem may be that you are attempting to register the same class name twice
each time you register a new class, it must have a unique class name string, unless it is one of the system control classes
you can use the same registered class name string to create more than one window, however

if you need further help, please attach complete code so that we can see all the constants and variables   :U

zekyr,
he is using GoAsm, i think
it is a syntax thing specific to that assembler   :P
if you want to dereference the handle as an address, it requires 2 instructions
mov eax,SomeLabel
mov eax,[eax]

raleeper

Quote from: dedndave on August 07, 2011, 01:06:33 PM
Ral,
the code you posted leaves a few things unclear
for example, i do not know what the value of lfstyle is, as you do not show it
as you have shown it being used, it should be an EQUate that represents a set of valid style bits

An oversight - it is defined by an equate: lfstyle      EQU   CS_HREDRAW or CS_VREDRAW or CS_DBLCLK

Quote
as for using the global class atom returned in RegisterClassEx as the lpClassName parameter,
that requires that the atom be converted to a 16-bit local atom - more trouble than it's worth

Roughly what I had guessed.

Quote
i think the problem may be that you are attempting to register the same class name twice
each time you register a new class, it must have a unique class name string
They do.

Quote
if you need further help, please attach complete code so that we can see all the constants and variables   :U

OK.  I'll see if I can figure out how to do that.  It's posted at www.raleeper.com.  Would a link be as good as attaching?

Thanks, ral

raleeper

Quote from: raleeper on August 07, 2011, 04:21:24 PM
Quote from: dedndave on August 07, 2011, 01:06:33 PM

if you need further help, please attach complete code so that we can see all the constants and variables   :U

QuoteOK.  I'll see if I can figure out how to do that.

Got it.  But if others are going to be looking at it, I'd better start cleaning it up.

[Later]  But to clarify, I'm not asking for further help at this point.  I had initially hoped that some dumb mistake might be obvious to the Forum experts.  As that was not true, I'll double-check and maybe rewrite everything.  Only after that will I ask for more help.[/Later]

Thanks, ral

raleeper

I was using (in effect) addresses instead of values in the class structure.  Truly a dumb mistake.  It might have taken me longer to get it if not for some early posts.

Now CreateWindowEx returns error (0), but the message is "The operation completed successfully."  I'll eventually figure this one out too, after I write the window procedure for the child window.

Thanks, ral

Gunner

No, a return value of 0 from CreateWindowEx does not mean "operation completed successfully"...  If CreateWindowEx returns NULL, you have to call GetLastError to get the correct error code.
~Rob (Gunner)
- IE Zone Editor
- Gunners File Type Editor
http://www.gunnerinc.com

dedndave

ok - that is due to the return value from CWProc
you cannot just use
CWProc:
xor eax,eax
ret


first, it would have to be a RET 16, as there are 4 dword parameters that need to be POP'ed
second, many of the messages sent to the WndProc function must be passed to DefWindowProc
the WndProc function is called during the execution of CreateWindowEx

try this.....

CWProc: JMP     DefWindowProc

if your assembler does not like that code, this should work
CWProc: push    ebp
        mov     ebp,esp
        INVOKE  DefWindowProc,[ebp+8],[ebp+12],[ebp+16],[ebp+20]
        pop     ebp
        ret     16


or even this   :P
CWProc: INVOKE  DefWindowProc,[esp+16],[esp+16],[esp+16],[esp+16]
        ret     16


with some assemblers, you can register DefWindowProc as the lpfnWndProc
then, you don't need a proc   :8)

raleeper

Quote from: Gunner on August 07, 2011, 05:35:32 PM
No, a return value of 0 from CreateWindowEx does not mean "operation completed successfully"...  If CreateWindowEx returns NULL, you have to call GetLastError to get the correct error code.

"operation completed successfully" is what I get fron GetLastError.