2 * PROJECT: ReactOS user32.dll
3 * COPYRIGHT: GPL - See COPYING in the top level directory
4 * FILE: dll/win32/user32/windows/class.c
5 * PURPOSE: Window classes
6 * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
8 * 09-05-2001 CSH Created
13 #include <wine/debug.h>
14 WINE_DEFAULT_DEBUG_CHANNEL(user32
);
16 /* From rtl/actctx.c and must match! */
19 DWORD kind
; // Activation context type
20 WCHAR
*name
; // Class name
21 WCHAR
*clsid
; // Not supported yet but needed for menu name.
26 WCHAR
*name
; // Dll name
36 LPCWSTR
*plpLibFileName
,
41 UNICODE_STRING SectionName
;
42 WCHAR SeactionNameBuf
[MAX_PATH
] = {0};
43 ACTCTX_SECTION_KEYED_DATA KeyedData
= { sizeof(KeyedData
) };
45 if (IS_ATOM(lpszClass
))
47 SectionName
.Buffer
= (LPWSTR
)&SeactionNameBuf
;
48 SectionName
.MaximumLength
= sizeof(SeactionNameBuf
);
49 if(!NtUserGetAtomName(LOWORD((DWORD_PTR
)lpszClass
), &SectionName
))
58 RtlCreateUnicodeStringFromAsciiz(&SectionName
, (LPSTR
)lpszClass
);
62 RtlInitUnicodeString(&SectionName
, lpszClass
);
65 Status
= RtlFindActivationContextSectionString( FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX
,
67 ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION
,
71 if (NT_SUCCESS(Status
) && KeyedData
.ulDataFormatVersion
== 1)
73 struct dll_redirect
*dll
= KeyedData
.lpSectionBase
;
75 if (plpLibFileName
) *plpLibFileName
= dll
->name
;
83 struct entity
*entity
= KeyedData
.lpData
;
85 FIXME("actctx: Needs to support menu name from redirected class!");
89 mnubuf
= entity
->clsid
;
92 mnuNameA
= (LPSTR
)lpszMenuName
;
93 RtlUnicodeToMultiByteN( mnuNameA
, 255, (PULONG
)&len
, mnubuf
, strlenW(mnubuf
) * sizeof(WCHAR
) );
98 mnuNameW
= (LPWSTR
)lpszMenuName
;
99 len
= strlenW(mnubuf
) * sizeof(WCHAR
);
100 RtlCopyMemory((void *)mnuNameW
, mnubuf
, len
);
105 if (pContext
) *pContext
= KeyedData
.hActCtx
;
108 if (!IS_ATOM(lpszClass
) && bAnsi
)
109 RtlFreeUnicodeString(&SectionName
);
110 if (KeyedData
.hActCtx
)
111 RtlReleaseActivationContext(KeyedData
.hActCtx
);
117 // Ref: http://yvs-it.blogspot.com/2010/04/initcommoncontrolsex.html
121 Real_VersionRegisterClass(
123 LPCWSTR lpLibFileName
,
125 HMODULE
* phLibModule
)
129 PREGISTERCLASSNAMEW pRegisterClassNameW
;
130 UNICODE_STRING ClassName
;
131 WCHAR ClassNameBuf
[MAX_PATH
] = {0};
132 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED Frame
= { sizeof(Frame
), 1 };
134 RtlActivateActivationContextUnsafeFast(&Frame
, Contex
);
141 hLibModule
= LoadLibraryW(lpLibFileName
);
144 if ((pRegisterClassNameW
= (void*) GetProcAddress(hLibModule
, "RegisterClassNameW")))
146 if (IS_ATOM(pszClass
))
148 ClassName
.Buffer
= (LPWSTR
)&ClassNameBuf
;
149 ClassName
.MaximumLength
= sizeof(ClassNameBuf
);
150 if (!NtUserGetAtomName(LOWORD((DWORD_PTR
)pszClass
), &ClassName
))
152 _SEH2_YIELD(goto Error_Exit
);
154 pszClass
= (PCWSTR
)&ClassNameBuf
;
156 Ret
= pRegisterClassNameW(pszClass
);
160 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
166 if ( Ret
|| !hLibModule
)
168 if ( phLibModule
) *phLibModule
= hLibModule
;
172 DWORD save_error
= GetLastError();
173 FreeLibrary(hLibModule
);
174 SetLastError(save_error
);
181 // Use wine hack to process extened context classes.
183 /***********************************************************************
186 static BOOL
is_comctl32_class( const WCHAR
*name
)
188 static const WCHAR classesW
[][20] =
190 {'C','o','m','b','o','B','o','x','E','x','3','2',0},
191 {'m','s','c','t','l','s','_','h','o','t','k','e','y','3','2',0},
192 {'m','s','c','t','l','s','_','p','r','o','g','r','e','s','s','3','2',0},
193 {'m','s','c','t','l','s','_','s','t','a','t','u','s','b','a','r','3','2',0},
194 {'m','s','c','t','l','s','_','t','r','a','c','k','b','a','r','3','2',0},
195 {'m','s','c','t','l','s','_','u','p','d','o','w','n','3','2',0},
196 {'N','a','t','i','v','e','F','o','n','t','C','t','l',0},
197 {'R','e','B','a','r','W','i','n','d','o','w','3','2',0},
198 {'S','y','s','A','n','i','m','a','t','e','3','2',0},
199 {'S','y','s','D','a','t','e','T','i','m','e','P','i','c','k','3','2',0},
200 {'S','y','s','H','e','a','d','e','r','3','2',0},
201 {'S','y','s','I','P','A','d','d','r','e','s','s','3','2',0},
202 {'S','y','s','L','i','s','t','V','i','e','w','3','2',0},
203 {'S','y','s','M','o','n','t','h','C','a','l','3','2',0},
204 {'S','y','s','P','a','g','e','r',0},
205 {'S','y','s','T','a','b','C','o','n','t','r','o','l','3','2',0},
206 {'S','y','s','T','r','e','e','V','i','e','w','3','2',0},
207 {'T','o','o','l','b','a','r','W','i','n','d','o','w','3','2',0},
208 {'t','o','o','l','t','i','p','s','_','c','l','a','s','s','3','2',0},
211 int min
= 0, max
= (sizeof(classesW
) / sizeof(classesW
[0])) - 1;
215 int res
, pos
= (min
+ max
) / 2;
216 if (!(res
= strcmpiW( name
, classesW
[pos
] ))) return TRUE
;
217 if (res
< 0) max
= pos
- 1;
225 VersionRegisterClass(
227 LPCWSTR lpLibFileName
,
229 HMODULE
* phLibModule
)
231 // Should be lpLibFileName.....
232 static const WCHAR comctl32W
[] = {'c','o','m','c','t','l','3','2','.','d','l','l',0};
234 PREGISTERCLASSNAMEW pRegisterClassNameW
;
235 UNICODE_STRING ClassName
;
236 WCHAR ClassNameBuf
[MAX_PATH
] = {0};
238 HMODULE hLibModule
= NULL
;
240 if (!IS_ATOM(pszClass
) && is_comctl32_class( pszClass
))
244 hLibModule
= LoadLibraryW(comctl32W
);
247 if ((pRegisterClassNameW
= (void*) GetProcAddress(hLibModule
, "RegisterClassNameW")))
249 if (IS_ATOM(pszClass
))
251 ClassName
.Buffer
= (LPWSTR
)&ClassNameBuf
;
252 ClassName
.MaximumLength
= sizeof(ClassNameBuf
);
253 if (!NtUserGetAtomName(LOWORD((DWORD_PTR
)pszClass
), &ClassName
))
255 ERR("Error while verifying ATOM\n");
256 _SEH2_YIELD(goto Error_Exit
);
258 pszClass
= (PCWSTR
)&ClassNameBuf
;
260 Ret
= pRegisterClassNameW(pszClass
);
264 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
270 if ( Ret
|| !hLibModule
)
272 if ( phLibModule
) *phLibModule
= hLibModule
;
276 DWORD save_error
= GetLastError();
277 FreeLibrary(hLibModule
);
278 SetLastError(save_error
);
280 TRACE( "%s retrying after loading comctl32\n", debugstr_w(pszClass
) );
283 TRACE("NO ComCtl32 Class %S!\n",pszClass
);
300 UNICODE_STRING ClassName
= {0};
302 HMODULE hLibModule
= NULL
;
304 BOOL Ret
, ClassFound
= FALSE
;
306 TRACE("%p class/atom: %s/%04x %p\n", hInstance
,
307 IS_ATOM(lpszClass
) ? NULL
: lpszClass
,
308 IS_ATOM(lpszClass
) ? lpszClass
: 0,
313 SetLastError( ERROR_NOACCESS
);
317 if (hInstance
== User32Instance
)
322 if (lpszClass
== NULL
)
324 SetLastError(ERROR_INVALID_PARAMETER
);
328 if (IS_ATOM(lpszClass
))
330 ClassName
.Buffer
= (PWSTR
)((ULONG_PTR
)lpszClass
);
334 if (!RtlCreateUnicodeStringFromAsciiz(&ClassName
,
337 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
342 if (!RegisterDefaultClasses
)
344 TRACE("RegisterSystemControls\n");
345 RegisterSystemControls();
350 Ret
= NtUserGetClassInfo( hInstance
,
352 (LPWNDCLASSEXW
)lpwcx
,
353 (LPWSTR
*)&pszMenuName
,
358 save_error
= GetLastError();
359 if ( save_error
== ERROR_CANNOT_FIND_WND_CLASS
||
360 save_error
== ERROR_CLASS_DOES_NOT_EXIST
)
362 ClassFound
= VersionRegisterClass(ClassName
.Buffer
, NULL
, NULL
, &hLibModule
);
363 if (ClassFound
) continue;
368 save_error
= GetLastError();
369 FreeLibrary(hLibModule
);
370 SetLastError(save_error
);
378 lpwcx
->lpszClassName
= lpszClass
;
379 // lpwcx->lpszMenuName = pszMenuName;
382 if (!IS_ATOM(lpszClass
))
384 RtlFreeUnicodeString(&ClassName
);
401 UNICODE_STRING ClassName
= {0};
403 HMODULE hLibModule
= NULL
;
405 BOOL Ret
, ClassFound
= FALSE
;
407 TRACE("%p class/atom: %S/%04x %p\n", hInstance
,
408 IS_ATOM(lpszClass
) ? NULL
: lpszClass
,
409 IS_ATOM(lpszClass
) ? lpszClass
: 0,
412 /* From wine, for speed only, ReactOS supports the correct return in
413 * Win32k. cbSize is ignored.
417 SetLastError( ERROR_NOACCESS
);
421 if (hInstance
== User32Instance
)
426 if (lpszClass
== NULL
)
428 SetLastError(ERROR_INVALID_PARAMETER
);
432 if (IS_ATOM(lpszClass
))
434 ClassName
.Buffer
= (PWSTR
)((ULONG_PTR
)lpszClass
);
438 RtlInitUnicodeString(&ClassName
,
442 if (!RegisterDefaultClasses
)
444 TRACE("RegisterSystemControls\n");
445 RegisterSystemControls();
450 Ret
= NtUserGetClassInfo( hInstance
,
458 save_error
= GetLastError();
459 if ( save_error
== ERROR_CANNOT_FIND_WND_CLASS
||
460 save_error
== ERROR_CLASS_DOES_NOT_EXIST
)
462 ClassFound
= VersionRegisterClass(ClassName
.Buffer
, NULL
, NULL
, &hLibModule
);
463 if (ClassFound
) continue;
468 save_error
= GetLastError();
469 FreeLibrary(hLibModule
);
470 SetLastError(save_error
);
478 lpwcx
->lpszClassName
= lpszClass
;
479 // lpwcx->lpszMenuName = pszMenuName;
493 LPWNDCLASSA lpWndClass
)
498 retval
= GetClassInfoExA(hInstance
, lpClassName
, &wcex
);
501 lpWndClass
->style
= wcex
.style
;
502 lpWndClass
->lpfnWndProc
= wcex
.lpfnWndProc
;
503 lpWndClass
->cbClsExtra
= wcex
.cbClsExtra
;
504 lpWndClass
->cbWndExtra
= wcex
.cbWndExtra
;
505 lpWndClass
->hInstance
= wcex
.hInstance
;
506 lpWndClass
->hIcon
= wcex
.hIcon
;
507 lpWndClass
->hCursor
= wcex
.hCursor
;
508 lpWndClass
->hbrBackground
= wcex
.hbrBackground
;
509 lpWndClass
->lpszMenuName
= wcex
.lpszMenuName
;
510 lpWndClass
->lpszClassName
= wcex
.lpszClassName
;
524 LPWNDCLASSW lpWndClass
)
529 retval
= GetClassInfoExW(hInstance
, lpClassName
, &wcex
);
532 lpWndClass
->style
= wcex
.style
;
533 lpWndClass
->lpfnWndProc
= wcex
.lpfnWndProc
;
534 lpWndClass
->cbClsExtra
= wcex
.cbClsExtra
;
535 lpWndClass
->cbWndExtra
= wcex
.cbWndExtra
;
536 lpWndClass
->hInstance
= wcex
.hInstance
;
537 lpWndClass
->hIcon
= wcex
.hIcon
;
538 lpWndClass
->hCursor
= wcex
.hCursor
;
539 lpWndClass
->hbrBackground
= wcex
.hbrBackground
;
540 lpWndClass
->lpszMenuName
= wcex
.lpszMenuName
;
541 lpWndClass
->lpszClassName
= wcex
.lpszClassName
;
547 // Based on find_winproc... Fixes many whine tests......
550 IntGetClsWndProc(PWND pWnd
, PCLS Class
, BOOL Ansi
)
553 ULONG_PTR gcpd
, Ret
= 0;
554 // If server side, sweep through proc list and return the client side proc.
555 if (Class
->CSF_flags
& CSF_SERVERSIDEPROC
)
556 { // Always scan through the list due to wine class "deftest".
557 for ( i
= FNID_FIRST
; i
<= FNID_SWITCH
; i
++)
559 if (GETPFNSERVER(i
) == Class
->lpfnWndProc
)
562 Ret
= (ULONG_PTR
)GETPFNCLIENTA(i
);
564 Ret
= (ULONG_PTR
)GETPFNCLIENTW(i
);
570 Ret
= (ULONG_PTR
)Class
->lpfnWndProc
;
571 // Return the proc if one of the FnId default class type.
572 if (Class
->fnid
<= FNID_GHOST
&& Class
->fnid
>= FNID_BUTTON
)
575 { // If match return the right proc by type.
576 if (GETPFNCLIENTW(Class
->fnid
) == Class
->lpfnWndProc
)
577 Ret
= (ULONG_PTR
)GETPFNCLIENTA(Class
->fnid
);
581 if (GETPFNCLIENTA(Class
->fnid
) == Class
->lpfnWndProc
)
582 Ret
= (ULONG_PTR
)GETPFNCLIENTW(Class
->fnid
);
585 // Return on change or Ansi/Unicode proc equal.
586 if ( Ret
!= (ULONG_PTR
)Class
->lpfnWndProc
||
587 Ansi
== !!(Class
->CSF_flags
& CSF_ANSIPROC
) )
590 /* We have an Ansi and Unicode swap! If Ansi create Unicode proc handle.
591 This will force CallWindowProc to deal with it. */
592 gcpd
= NtUserGetCPD( UserHMGetHandle(pWnd
),
593 (Ansi
? UserGetCPDA2U
: UserGetCPDU2A
)|UserGetCPDWndtoCls
,
596 return (gcpd
? gcpd
: Ret
);
600 // Based on IntGetClsWndProc
603 IntGetWndProc(PWND pWnd
, BOOL Ansi
)
606 WNDPROC gcpd
, Ret
= 0;
607 PCLS Class
= DesktopPtrToUser(pWnd
->pcls
);
609 if (!Class
) return Ret
;
611 if (pWnd
->state
& WNDS_SERVERSIDEWINDOWPROC
)
613 for ( i
= FNID_FIRST
; i
<= FNID_SWITCH
; i
++)
615 if (GETPFNSERVER(i
) == pWnd
->lpfnWndProc
)
618 Ret
= GETPFNCLIENTA(i
);
620 Ret
= GETPFNCLIENTW(i
);
626 /* Edit controls are special - they return a wndproc handle when
627 GetWindowLongPtr is called with a different A/W.
628 On the other hand there is no W->A->W conversion so this control
629 is treated specially.
631 if (Class
->fnid
== FNID_EDIT
)
632 Ret
= pWnd
->lpfnWndProc
;
636 Ret
= pWnd
->lpfnWndProc
;
638 if (Class
->fnid
<= FNID_GHOST
&& Class
->fnid
>= FNID_BUTTON
)
642 if (GETPFNCLIENTW(Class
->fnid
) == pWnd
->lpfnWndProc
)
643 Ret
= GETPFNCLIENTA(Class
->fnid
);
647 if (GETPFNCLIENTA(Class
->fnid
) == pWnd
->lpfnWndProc
)
648 Ret
= GETPFNCLIENTW(Class
->fnid
);
651 // Return on the change.
652 if ( Ret
!= pWnd
->lpfnWndProc
)
656 if ( Ansi
== !!(pWnd
->state
& WNDS_ANSIWINDOWPROC
) )
659 gcpd
= (WNDPROC
)NtUserGetCPD( UserHMGetHandle(pWnd
),
660 (Ansi
? UserGetCPDA2U
: UserGetCPDU2A
)|UserGetCPDWindow
,
663 return (gcpd
? gcpd
: Ret
);
666 static ULONG_PTR FASTCALL
667 IntGetClassLongA(PWND Wnd
, PCLS Class
, int nIndex
)
673 if (nIndex
+ sizeof(ULONG_PTR
) < nIndex
||
674 nIndex
+ sizeof(ULONG_PTR
) > Class
->cbclsExtra
)
676 SetLastError(ERROR_INVALID_PARAMETER
);
679 Ret
= *(PULONG_PTR
)((ULONG_PTR
)(Class
+ 1) + nIndex
);
686 Ret
= (ULONG_PTR
)Class
->cbwndExtra
;
690 Ret
= (ULONG_PTR
)Class
->cbclsExtra
;
693 case GCL_HBRBACKGROUND
:
694 Ret
= (ULONG_PTR
)Class
->hbrBackground
;
695 if (Ret
!= 0 && Ret
< 0x4000)
696 Ret
= (ULONG_PTR
)GetSysColorBrush((ULONG
)Ret
- 1);
700 //ERR("Cls 0x%x GCL_HMODULE 0x%x\n", Wnd->pcls, Class->hModule);
701 Ret
= (ULONG_PTR
)Class
->hModule
;
705 Ret
= (ULONG_PTR
)Class
->lpszClientAnsiMenuName
;
709 Ret
= (ULONG_PTR
)Class
->style
;
713 Ret
= (ULONG_PTR
)Class
->atomClassName
;
715 #ifdef NEW_CURSORICON
717 Ret
= Class
->spcur
? (ULONG_PTR
)((PPROCMARKHEAD
)DesktopPtrToUser(Class
->spcur
))->h
: 0;
721 Ret
= Class
->spicn
? (ULONG_PTR
)((PPROCMARKHEAD
)DesktopPtrToUser(Class
->spicn
))->h
: 0;
725 Ret
= Class
->spicnSm
? (ULONG_PTR
)((PPROCMARKHEAD
)DesktopPtrToUser(Class
->spicnSm
))->h
: 0;
729 /* FIXME - get handle from pointer to CURSOR object */
730 Ret
= (ULONG_PTR
)Class
->hCursor
;
734 /* FIXME - get handle from pointer to ICON object */
735 Ret
= (ULONG_PTR
)Class
->hIcon
;
739 /* FIXME - get handle from pointer to ICON object */
740 Ret
= (ULONG_PTR
)(Class
->hIconSm
? Class
->hIconSm
: Class
->hIconSmIntern
);
745 Ret
= IntGetClsWndProc(Wnd
, Class
, TRUE
);
749 SetLastError(ERROR_INVALID_INDEX
);
757 static ULONG_PTR FASTCALL
758 IntGetClassLongW (PWND Wnd
, PCLS Class
, int nIndex
)
764 if (nIndex
+ sizeof(ULONG_PTR
) < nIndex
||
765 nIndex
+ sizeof(ULONG_PTR
) > Class
->cbclsExtra
)
767 SetLastError(ERROR_INVALID_PARAMETER
);
770 Ret
= *(PULONG_PTR
)((ULONG_PTR
)(Class
+ 1) + nIndex
);
777 Ret
= (ULONG_PTR
)Class
->cbwndExtra
;
781 Ret
= (ULONG_PTR
)Class
->cbclsExtra
;
784 case GCLP_HBRBACKGROUND
:
785 Ret
= (ULONG_PTR
)Class
->hbrBackground
;
786 if (Ret
!= 0 && Ret
< 0x4000)
787 Ret
= (ULONG_PTR
)GetSysColorBrush((ULONG
)Ret
- 1);
791 Ret
= (ULONG_PTR
)Class
->hModule
;
795 Ret
= (ULONG_PTR
)Class
->lpszClientUnicodeMenuName
;
799 Ret
= (ULONG_PTR
)Class
->style
;
803 Ret
= (ULONG_PTR
)Class
->atomClassName
;
806 #ifdef NEW_CURSORICON
808 Ret
= Class
->spcur
? (ULONG_PTR
)((PPROCMARKHEAD
)DesktopPtrToUser(Class
->spcur
))->h
: 0;
812 Ret
= Class
->spicn
? (ULONG_PTR
)((PPROCMARKHEAD
)DesktopPtrToUser(Class
->spicn
))->h
: 0;
816 Ret
= Class
->spicnSm
? (ULONG_PTR
)((PPROCMARKHEAD
)DesktopPtrToUser(Class
->spicnSm
))->h
: 0;
820 /* FIXME - get handle from pointer to CURSOR object */
821 Ret
= (ULONG_PTR
)Class
->hCursor
;
825 /* FIXME - get handle from pointer to ICON object */
826 Ret
= (ULONG_PTR
)Class
->hIcon
;
830 /* FIXME - get handle from pointer to ICON object */
831 Ret
= (ULONG_PTR
)(Class
->hIconSm
? Class
->hIconSm
: Class
->hIconSmIntern
);
836 Ret
= IntGetClsWndProc(Wnd
, Class
, FALSE
);
840 SetLastError(ERROR_INVALID_INDEX
);
852 GetClassLongA(HWND hWnd
, int nIndex
)
858 TRACE("%p %d\n", hWnd
, nIndex
);
860 Wnd
= ValidateHwnd(hWnd
);
866 Class
= DesktopPtrToUser(Wnd
->pcls
);
872 case GCLP_HBRBACKGROUND
:
879 SetLastError(ERROR_INVALID_INDEX
);
883 Ret
= IntGetClassLongA(Wnd
, Class
, nIndex
);
887 Ret
= IntGetClassLongA(Wnd
, Class
, nIndex
);
892 WARN("Invalid class for hwnd 0x%p!\n", hWnd
);
895 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
908 GetClassLongW ( HWND hWnd
, int nIndex
)
914 TRACE("%p %d\n", hWnd
, nIndex
);
916 Wnd
= ValidateHwnd(hWnd
);
922 Class
= DesktopPtrToUser(Wnd
->pcls
);
928 case GCLP_HBRBACKGROUND
:
935 SetLastError(ERROR_INVALID_INDEX
);
939 Ret
= IntGetClassLongW(Wnd
, Class
, nIndex
);
943 Ret
= IntGetClassLongW(Wnd
, Class
, nIndex
);
948 WARN("Invalid class for hwnd 0x%p!\n", hWnd
);
951 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
966 GetClassLongPtrA(HWND hWnd
,
973 TRACE("%p %d\n", hWnd
, nIndex
);
975 Wnd
= ValidateHwnd(hWnd
);
981 Class
= DesktopPtrToUser(Wnd
->pcls
);
984 Ret
= IntGetClassLongA(Wnd
, Class
, nIndex
);
988 WARN("Invalid class for hwnd 0x%p!\n", hWnd
);
991 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1005 GetClassLongPtrW(HWND hWnd
,
1012 TRACE("%p %d\n", hWnd
, nIndex
);
1014 Wnd
= ValidateHwnd(hWnd
);
1020 Class
= DesktopPtrToUser(Wnd
->pcls
);
1023 Ret
= IntGetClassLongW(Wnd
, Class
, nIndex
);
1027 WARN("Invalid class for hwnd 0x%p!\n", hWnd
);
1030 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1050 WCHAR tmpbuf
[MAX_ATOM_LEN
+ 1];
1053 if (nMaxCount
<= 0) return 0;
1054 if (!GetClassNameW( hWnd
, tmpbuf
, sizeof(tmpbuf
)/sizeof(WCHAR
) )) return 0;
1055 RtlUnicodeToMultiByteN( lpClassName
, nMaxCount
- 1, (PULONG
)&len
, tmpbuf
, strlenW(tmpbuf
) * sizeof(WCHAR
) );
1056 lpClassName
[len
] = 0;
1058 TRACE("%p class/atom: %s/%04x %x\n", hWnd
,
1059 IS_ATOM(lpClassName
) ? NULL
: lpClassName
,
1060 IS_ATOM(lpClassName
) ? lpClassName
: 0,
1077 UNICODE_STRING ClassName
;
1080 ClassName
.MaximumLength
= nMaxCount
* sizeof(WCHAR
);
1081 ClassName
.Buffer
= lpClassName
;
1083 Result
= NtUserGetClassName(hWnd
,
1087 TRACE("%p class/atom: %S/%04x %x\n", hWnd
,
1088 IS_ATOM(lpClassName
) ? NULL
: lpClassName
,
1089 IS_ATOM(lpClassName
) ? lpClassName
: 0,
1109 if (offset
< 0) return GetClassLongA( hwnd
, offset
);
1111 Wnd
= ValidateHwnd(hwnd
);
1115 class = DesktopPtrToUser(Wnd
->pcls
);
1116 if (class == NULL
) return 0;
1118 if (offset
<= class->cbclsExtra
- sizeof(WORD
))
1119 memcpy( &retvalue
, (char *)(class + 1) + offset
, sizeof(retvalue
) );
1121 SetLastError( ERROR_INVALID_INDEX
);
1127 LONG_PTR
IntGetWindowLong( HWND hwnd
, INT offset
, UINT size
, BOOL unicode
)
1129 LONG_PTR retvalue
= 0;
1132 if (offset
== GWLP_HWNDPARENT
)
1134 HWND parent
= GetAncestor( hwnd
, GA_PARENT
);
1135 if (parent
== GetDesktopWindow()) parent
= GetWindow( hwnd
, GW_OWNER
);
1136 return (ULONG_PTR
)parent
;
1139 if (!(wndPtr
= ValidateHwnd( hwnd
)))
1141 SetLastError( ERROR_INVALID_WINDOW_HANDLE
);
1147 if (offset
> (int)(wndPtr
->cbwndExtra
- size
))
1149 WARN("Invalid offset %d\n", offset
);
1150 SetLastError( ERROR_INVALID_INDEX
);
1153 retvalue
= *((LONG_PTR
*)((PCHAR
)(wndPtr
+ 1) + offset
));
1155 /* WINE: special case for dialog window procedure */
1156 //if ((offset == DWLP_DLGPROC) && (size == sizeof(LONG_PTR)) && (wndPtr->flags & WIN_ISDIALOG))
1157 // retvalue = (LONG_PTR)IntGetWndProc( (WNDPROC)retvalue, unicode );
1163 case GWLP_USERDATA
: retvalue
= wndPtr
->dwUserData
; break;
1164 case GWL_STYLE
: retvalue
= wndPtr
->style
; break;
1165 case GWL_EXSTYLE
: retvalue
= wndPtr
->ExStyle
; break;
1166 case GWLP_ID
: retvalue
= wndPtr
->IDMenu
; break;
1167 case GWLP_HINSTANCE
: retvalue
= (ULONG_PTR
)wndPtr
->hModule
; break;
1170 if (!TestWindowProcess(wndPtr
))
1172 SetLastError(ERROR_ACCESS_DENIED
);
1175 retvalue
= (ULONG_PTR
)IntGetWndProc(wndPtr
, !unicode
);
1179 WARN("Unknown offset %d\n", offset
);
1180 SetLastError( ERROR_INVALID_INDEX
);
1191 GetWindowLongA ( HWND hWnd
, int nIndex
)
1193 return IntGetWindowLong( hWnd
, nIndex
, sizeof(LONG
), FALSE
);
1201 GetWindowLongW(HWND hWnd
, int nIndex
)
1203 return IntGetWindowLong( hWnd
, nIndex
, sizeof(LONG
), TRUE
);
1212 GetWindowLongPtrA(HWND hWnd
,
1215 return IntGetWindowLong( hWnd
, nIndex
, sizeof(LONG_PTR
), FALSE
);
1223 GetWindowLongPtrW(HWND hWnd
,
1226 return IntGetWindowLong( hWnd
, nIndex
, sizeof(LONG_PTR
), TRUE
);
1236 GetWindowWord(HWND hWnd
, int nIndex
)
1241 case GWLP_HINSTANCE
:
1242 case GWLP_HWNDPARENT
:
1247 WARN("Invalid offset %d\n", nIndex
);
1248 SetLastError( ERROR_INVALID_INDEX
);
1253 return IntGetWindowLong( hWnd
, nIndex
, sizeof(WORD
), FALSE
);
1261 RealGetWindowClassW(
1266 UNICODE_STRING ClassName
;
1267 ClassName
.MaximumLength
= cchType
* sizeof(WCHAR
);
1268 ClassName
.Buffer
= (PWSTR
)pszType
;
1270 return NtUserGetClassName(hwnd
,TRUE
,&ClassName
);
1279 RealGetWindowClassA(
1284 WCHAR tmpbuf
[MAX_ATOM_LEN
+ 1];
1287 if ((INT
)cchType
<= 0) return 0;
1288 if (!RealGetWindowClassW( hwnd
, tmpbuf
, sizeof(tmpbuf
)/sizeof(WCHAR
) )) return 0;
1289 RtlUnicodeToMultiByteN( pszType
, cchType
- 1, (PULONG
)&len
, tmpbuf
, strlenW(tmpbuf
) * sizeof(WCHAR
) );
1295 * Create a small icon based on a standard icon
1297 #if 0 // Keep vintage code from revision 18764 by GvG!
1299 CreateSmallIcon(HICON StdIcon
)
1301 HICON SmallIcon
= NULL
;
1304 int SmallIconHeight
;
1305 BITMAP StdBitmapInfo
;
1306 HDC hSourceDc
= NULL
;
1309 HBITMAP OldSourceBitmap
= NULL
;
1310 HBITMAP OldDestBitmap
= NULL
;
1312 SmallInfo
.hbmColor
= NULL
;
1313 SmallInfo
.hbmMask
= NULL
;
1315 /* We need something to work with... */
1316 if (NULL
== StdIcon
)
1321 SmallIconWidth
= GetSystemMetrics(SM_CXSMICON
);
1322 SmallIconHeight
= GetSystemMetrics(SM_CYSMICON
);
1323 if (! GetIconInfo(StdIcon
, &StdInfo
))
1325 ERR("Failed to get icon info for icon 0x%x\n", StdIcon
);
1328 if (! GetObjectW(StdInfo
.hbmMask
, sizeof(BITMAP
), &StdBitmapInfo
))
1330 ERR("Failed to get bitmap info for icon 0x%x bitmap 0x%x\n",
1331 StdIcon
, StdInfo
.hbmColor
);
1334 if (StdBitmapInfo
.bmWidth
== SmallIconWidth
&&
1335 StdBitmapInfo
.bmHeight
== SmallIconHeight
)
1337 /* Icon already has the correct dimensions */
1341 hSourceDc
= CreateCompatibleDC(NULL
);
1342 if (NULL
== hSourceDc
)
1344 ERR("Failed to create source DC\n");
1347 hDestDc
= CreateCompatibleDC(NULL
);
1348 if (NULL
== hDestDc
)
1350 ERR("Failed to create dest DC\n");
1354 OldSourceBitmap
= SelectObject(hSourceDc
, StdInfo
.hbmColor
);
1355 if (NULL
== OldSourceBitmap
)
1357 ERR("Failed to select source color bitmap\n");
1360 SmallInfo
.hbmColor
= CreateCompatibleBitmap(hSourceDc
, SmallIconWidth
,
1362 if (NULL
== SmallInfo
.hbmColor
)
1364 ERR("Failed to create color bitmap\n");
1367 OldDestBitmap
= SelectObject(hDestDc
, SmallInfo
.hbmColor
);
1368 if (NULL
== OldDestBitmap
)
1370 ERR("Failed to select dest color bitmap\n");
1373 if (! StretchBlt(hDestDc
, 0, 0, SmallIconWidth
, SmallIconHeight
,
1374 hSourceDc
, 0, 0, StdBitmapInfo
.bmWidth
,
1375 StdBitmapInfo
.bmHeight
, SRCCOPY
))
1377 ERR("Failed to stretch color bitmap\n");
1381 if (NULL
== SelectObject(hSourceDc
, StdInfo
.hbmMask
))
1383 ERR("Failed to select source mask bitmap\n");
1386 SmallInfo
.hbmMask
= CreateCompatibleBitmap(hSourceDc
, SmallIconWidth
, SmallIconHeight
);
1387 if (NULL
== SmallInfo
.hbmMask
)
1389 ERR("Failed to create mask bitmap\n");
1392 if (NULL
== SelectObject(hDestDc
, SmallInfo
.hbmMask
))
1394 ERR("Failed to select dest mask bitmap\n");
1397 if (! StretchBlt(hDestDc
, 0, 0, SmallIconWidth
, SmallIconHeight
,
1398 hSourceDc
, 0, 0, StdBitmapInfo
.bmWidth
,
1399 StdBitmapInfo
.bmHeight
, SRCCOPY
))
1401 ERR("Failed to stretch mask bitmap\n");
1405 SmallInfo
.fIcon
= TRUE
;
1406 SmallInfo
.xHotspot
= SmallIconWidth
/ 2;
1407 SmallInfo
.yHotspot
= SmallIconHeight
/ 2;
1408 SmallIcon
= CreateIconIndirect(&SmallInfo
);
1409 if (NULL
== SmallIcon
)
1411 ERR("Failed to create icon\n");
1416 if (NULL
!= SmallInfo
.hbmMask
)
1418 DeleteObject(SmallInfo
.hbmMask
);
1420 if (NULL
!= OldDestBitmap
)
1422 SelectObject(hDestDc
, OldDestBitmap
);
1424 if (NULL
!= SmallInfo
.hbmColor
)
1426 DeleteObject(SmallInfo
.hbmColor
);
1428 if (NULL
!= hDestDc
)
1432 if (NULL
!= OldSourceBitmap
)
1434 SelectObject(hSourceDc
, OldSourceBitmap
);
1436 if (NULL
!= hSourceDc
)
1438 DeleteDC(hSourceDc
);
1446 RegisterClassExWOWW(WNDCLASSEXW
*lpwcx
,
1453 WNDCLASSEXW WndClass
;
1454 UNICODE_STRING ClassName
;
1455 UNICODE_STRING MenuName
= {0};
1456 CLSMENUNAME clsMenuName
;
1457 ANSI_STRING AnsiMenuName
;
1458 HMODULE hLibModule
= NULL
;
1460 BOOL ClassFound
= FALSE
;
1462 if (lpwcx
== NULL
|| lpwcx
->cbSize
!= sizeof(WNDCLASSEXW
) ||
1463 lpwcx
->cbClsExtra
< 0 || lpwcx
->cbWndExtra
< 0 ||
1464 lpwcx
->lpszClassName
== NULL
)
1466 TRACE("RegisterClassExWOWW Invalid Parameter Error!\n");
1467 SetLastError(ERROR_INVALID_PARAMETER
);
1473 if (!RegisterDefaultClasses
) RegisterSystemControls();
1476 * On real Windows this looks more like:
1477 * if (lpwcx->hInstance == User32Instance &&
1478 * *(PULONG)((ULONG_PTR)NtCurrentTeb() + 0x6D4) & 0x400)
1479 * But since I have no idea what the magic field in the
1480 * TEB structure means, I rather decided to omit that.
1483 GetWin32ClientInfo()->dwExpWinVer & (WINVER == 0x400)
1485 if (lpwcx
->hInstance
== User32Instance
)
1487 TRACE("RegisterClassExWOWW User32Instance!\n");
1488 SetLastError(ERROR_INVALID_PARAMETER
);
1491 /* Yes, this is correct. We should modify the passed structure. */
1492 if (lpwcx
->hInstance
== NULL
)
1493 ((WNDCLASSEXW
*)lpwcx
)->hInstance
= GetModuleHandleW(NULL
);
1495 RtlCopyMemory(&WndClass
, lpwcx
, sizeof(WNDCLASSEXW
));
1497 if (NULL == WndClass.hIconSm)
1499 WndClass.hIconSm = CreateSmallIcon(WndClass.hIcon);
1502 RtlInitEmptyAnsiString(&AnsiMenuName
, NULL
, 0);
1503 if (WndClass
.lpszMenuName
!= NULL
)
1505 if (!IS_INTRESOURCE(WndClass
.lpszMenuName
))
1507 if (WndClass
.lpszMenuName
[0])
1509 RtlInitUnicodeString(&MenuName
, WndClass
.lpszMenuName
);
1510 RtlUnicodeStringToAnsiString( &AnsiMenuName
, &MenuName
, TRUE
);
1515 MenuName
.Buffer
= (LPWSTR
)WndClass
.lpszMenuName
;
1516 AnsiMenuName
.Buffer
= (PCHAR
)WndClass
.lpszMenuName
;
1520 if (IS_ATOM(WndClass
.lpszClassName
))
1523 ClassName
.MaximumLength
= 0;
1524 ClassName
.Buffer
= (LPWSTR
)WndClass
.lpszClassName
;
1528 RtlInitUnicodeString(&ClassName
, WndClass
.lpszClassName
);
1531 clsMenuName
.pszClientAnsiMenuName
= AnsiMenuName
.Buffer
;
1532 clsMenuName
.pwszClientUnicodeMenuName
= MenuName
.Buffer
;
1533 clsMenuName
.pusMenuName
= &MenuName
;
1537 Atom
= NtUserRegisterClassExWOW( &WndClass
,
1539 NULL
, //PUNICODE_STRING ClsNVersion,
1548 save_error
= GetLastError();
1549 if ( save_error
== ERROR_CANNOT_FIND_WND_CLASS
||
1550 save_error
== ERROR_CLASS_DOES_NOT_EXIST
)
1552 ClassFound
= VersionRegisterClass(ClassName
.Buffer
, NULL
, NULL
, &hLibModule
);
1553 if (ClassFound
) continue;
1558 save_error
= GetLastError();
1559 FreeLibrary(hLibModule
);
1560 SetLastError(save_error
);
1566 TRACE("atom=%04x wndproc=%p hinst=%p bg=%p style=%08x clsExt=%d winExt=%d class=%p\n",
1567 Atom
, lpwcx
->lpfnWndProc
, lpwcx
->hInstance
, lpwcx
->hbrBackground
,
1568 lpwcx
->style
, lpwcx
->cbClsExtra
, lpwcx
->cbWndExtra
, WndClass
);
1577 RegisterClassExA(CONST WNDCLASSEXA
*lpwcx
)
1580 WNDCLASSEXW WndClass
;
1581 WCHAR mname
[MAX_BUFFER_LEN
];
1582 WCHAR cname
[MAX_BUFFER_LEN
];
1584 RtlCopyMemory(&WndClass
, lpwcx
, sizeof(WNDCLASSEXA
));
1586 if (WndClass
.lpszMenuName
!= NULL
)
1588 if (!IS_INTRESOURCE(WndClass
.lpszMenuName
))
1590 if (WndClass
.lpszMenuName
[0])
1592 if (!MultiByteToWideChar( CP_ACP
, 0, lpwcx
->lpszMenuName
, -1, mname
, MAX_ATOM_LEN
+ 1 )) return 0;
1594 WndClass
.lpszMenuName
= mname
;
1599 if (!IS_ATOM(WndClass
.lpszClassName
))
1601 if (!MultiByteToWideChar( CP_ACP
, 0, lpwcx
->lpszClassName
, -1, cname
, MAX_ATOM_LEN
+ 1 )) return 0;
1603 WndClass
.lpszClassName
= cname
;
1606 Atom
= RegisterClassExWOWW( &WndClass
,
1612 TRACE("A atom=%04x wndproc=%p hinst=%p bg=%p style=%08x clsExt=%d winExt=%d class=%p\n",
1613 Atom
, lpwcx
->lpfnWndProc
, lpwcx
->hInstance
, lpwcx
->hbrBackground
,
1614 lpwcx
->style
, lpwcx
->cbClsExtra
, lpwcx
->cbWndExtra
, WndClass
);
1623 RegisterClassExW(CONST WNDCLASSEXW
*lpwcx
)
1627 Atom
= RegisterClassExWOWW( (WNDCLASSEXW
*)lpwcx
, 0, 0, 0, TRUE
);
1629 TRACE("W atom=%04x wndproc=%p hinst=%p bg=%p style=%08x clsExt=%d winExt=%d\n",
1630 Atom
, lpwcx
->lpfnWndProc
, lpwcx
->hInstance
, lpwcx
->hbrBackground
,
1631 lpwcx
->style
, lpwcx
->cbClsExtra
, lpwcx
->cbWndExtra
);
1640 RegisterClassA(CONST WNDCLASSA
*lpWndClass
)
1644 if (lpWndClass
== NULL
)
1647 RtlCopyMemory(&Class
.style
, lpWndClass
, sizeof(WNDCLASSA
));
1648 Class
.cbSize
= sizeof(WNDCLASSEXA
);
1649 Class
.hIconSm
= NULL
;
1651 return RegisterClassExA(&Class
);
1658 RegisterClassW(CONST WNDCLASSW
*lpWndClass
)
1662 if (lpWndClass
== NULL
)
1665 RtlCopyMemory(&Class
.style
, lpWndClass
, sizeof(WNDCLASSW
));
1666 Class
.cbSize
= sizeof(WNDCLASSEXW
);
1667 Class
.hIconSm
= NULL
;
1669 return RegisterClassExW(&Class
);
1677 SetClassLongA (HWND hWnd
,
1681 PSTR lpStr
= (PSTR
)(ULONG_PTR
)dwNewLong
;
1682 UNICODE_STRING Value
= {0};
1683 BOOL Allocated
= FALSE
;
1686 /* FIXME - portability!!!! */
1688 if (nIndex
== GCL_MENUNAME
&& lpStr
!= NULL
)
1690 if (!IS_INTRESOURCE(lpStr
))
1692 if (!RtlCreateUnicodeStringFromAsciiz(&Value
,
1695 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1702 Value
.Buffer
= (PWSTR
)lpStr
;
1704 dwNewLong
= (LONG_PTR
)&Value
;
1706 else if (nIndex
== GCW_ATOM
&& lpStr
!= NULL
)
1708 if (!IS_ATOM(lpStr
))
1710 if (!RtlCreateUnicodeStringFromAsciiz(&Value
,
1713 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1720 Value
.Buffer
= (PWSTR
)lpStr
;
1722 dwNewLong
= (LONG_PTR
)&Value
;
1725 Ret
= (DWORD
)NtUserSetClassLong(hWnd
,
1732 RtlFreeUnicodeString(&Value
);
1744 SetClassLongW(HWND hWnd
,
1748 PWSTR lpStr
= (PWSTR
)(ULONG_PTR
)dwNewLong
;
1749 UNICODE_STRING Value
= {0};
1751 TRACE("%p %d %lx\n", hWnd
, nIndex
, dwNewLong
);
1753 /* FIXME - portability!!!! */
1755 if (nIndex
== GCL_MENUNAME
&& lpStr
!= NULL
)
1757 if (!IS_INTRESOURCE(lpStr
))
1759 RtlInitUnicodeString(&Value
,
1763 Value
.Buffer
= lpStr
;
1765 dwNewLong
= (LONG_PTR
)&Value
;
1767 else if (nIndex
== GCW_ATOM
&& lpStr
!= NULL
)
1769 if (!IS_ATOM(lpStr
))
1771 RtlInitUnicodeString(&Value
,
1775 Value
.Buffer
= lpStr
;
1777 dwNewLong
= (LONG_PTR
)&Value
;
1780 return (DWORD
)NtUserSetClassLong(hWnd
,
1792 SetClassLongPtrA(HWND hWnd
,
1805 SetClassLongPtrW(HWND hWnd
,
1824 * NOTE: Obsoleted in 32-bit windows
1827 if ((nIndex
< 0) && (nIndex
!= GCW_ATOM
))
1830 return (WORD
) SetClassLongW ( hWnd
, nIndex
, wNewWord
);
1838 SetWindowWord ( HWND hWnd
,int nIndex
,WORD wNewWord
)
1843 case GWLP_HINSTANCE
:
1844 case GWLP_HWNDPARENT
:
1849 WARN("Invalid offset %d\n", nIndex
);
1850 SetLastError( ERROR_INVALID_INDEX
);
1855 return NtUserSetWindowLong( hWnd
, nIndex
, wNewWord
, FALSE
);
1869 return NtUserSetWindowLong(hWnd
, nIndex
, dwNewLong
, TRUE
);
1882 return NtUserSetWindowLong(hWnd
, nIndex
, dwNewLong
, FALSE
);
1891 SetWindowLongPtrA(HWND hWnd
,
1895 return NtUserSetWindowLong(hWnd
, nIndex
, dwNewLong
, FALSE
);
1903 SetWindowLongPtrW(HWND hWnd
,
1907 return NtUserSetWindowLong(hWnd
, nIndex
, dwNewLong
, FALSE
);
1918 HINSTANCE hInstance
)
1920 UNICODE_STRING ClassName
= {0};
1923 TRACE("class/atom: %s/%04x %p\n",
1924 IS_ATOM(lpClassName
) ? NULL
: lpClassName
,
1925 IS_ATOM(lpClassName
) ? lpClassName
: 0,
1928 if (!IS_ATOM(lpClassName
))
1930 if (!RtlCreateUnicodeStringFromAsciiz(&ClassName
,
1933 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1938 ClassName
.Buffer
= (PWSTR
)((ULONG_PTR
)lpClassName
);
1940 Ret
= NtUserUnregisterClass(&ClassName
,
1944 if (!IS_ATOM(lpClassName
))
1945 RtlFreeUnicodeString(&ClassName
);
1957 LPCWSTR lpClassName
,
1958 HINSTANCE hInstance
)
1960 UNICODE_STRING ClassName
= {0};
1962 TRACE("class/atom: %S/%04x %p\n",
1963 IS_ATOM(lpClassName
) ? NULL
: lpClassName
,
1964 IS_ATOM(lpClassName
) ? lpClassName
: 0,
1967 if (!IS_ATOM(lpClassName
))
1969 RtlInitUnicodeString(&ClassName
,
1973 ClassName
.Buffer
= (PWSTR
)((ULONG_PTR
)lpClassName
);
1975 return NtUserUnregisterClass(&ClassName
,