2 * PROJECT: ReactOS user32.dll
3 * COPYRIGHT: GPL - See COPYING in the top level directory
4 * FILE: win32ss/user/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 #define USE_VERSIONED_CLASSES
18 /* From rtl/actctx.c and must match! */
19 struct strsection_header
31 struct wndclass_redirect_data
36 ULONG name_offset
; /* versioned name offset */
38 ULONG module_offset
;/* container name offset */
42 // Use wine hack to process extended context classes.
44 /***********************************************************************
47 LPCWSTR
is_comctl32_class( const WCHAR
*name
)
49 static const WCHAR classesW
[][20] =
51 {'C','o','m','b','o','B','o','x','E','x','3','2',0},
52 {'m','s','c','t','l','s','_','h','o','t','k','e','y','3','2',0},
53 {'m','s','c','t','l','s','_','p','r','o','g','r','e','s','s','3','2',0},
54 {'m','s','c','t','l','s','_','s','t','a','t','u','s','b','a','r','3','2',0},
55 {'m','s','c','t','l','s','_','t','r','a','c','k','b','a','r','3','2',0},
56 {'m','s','c','t','l','s','_','u','p','d','o','w','n','3','2',0},
57 {'N','a','t','i','v','e','F','o','n','t','C','t','l',0},
58 {'R','e','B','a','r','W','i','n','d','o','w','3','2',0},
59 {'S','y','s','A','n','i','m','a','t','e','3','2',0},
60 {'S','y','s','D','a','t','e','T','i','m','e','P','i','c','k','3','2',0},
61 {'S','y','s','H','e','a','d','e','r','3','2',0},
62 {'S','y','s','I','P','A','d','d','r','e','s','s','3','2',0},
63 {'S','y','s','L','i','s','t','V','i','e','w','3','2',0},
64 {'S','y','s','M','o','n','t','h','C','a','l','3','2',0},
65 {'S','y','s','P','a','g','e','r',0},
66 {'S','y','s','T','a','b','C','o','n','t','r','o','l','3','2',0},
67 {'S','y','s','T','r','e','e','V','i','e','w','3','2',0},
68 {'T','o','o','l','b','a','r','W','i','n','d','o','w','3','2',0},
69 {'t','o','o','l','t','i','p','s','_','c','l','a','s','s','3','2',0},
72 int min
= 0, max
= (sizeof(classesW
) / sizeof(classesW
[0])) - 1;
76 int res
, pos
= (min
+ max
) / 2;
77 if (!(res
= strcmpiW( name
, classesW
[pos
] ))) return classesW
[pos
];
78 if (res
< 0) max
= pos
- 1;
87 const void* lpszClass
,
89 LPCWSTR
*plpLibFileName
,
93 LPCWSTR VersionedClass
= NULL
;
95 UNICODE_STRING SectionName
;
96 WCHAR SectionNameBuf
[MAX_PATH
] = {0};
97 ACTCTX_SECTION_KEYED_DATA KeyedData
= { sizeof(KeyedData
) };
101 ERR("Null class given !\n");
105 if (IS_ATOM(lpszClass
))
107 RtlInitEmptyUnicodeString(&SectionName
, SectionNameBuf
, sizeof(SectionNameBuf
));
108 if(!NtUserGetAtomName(LOWORD((DWORD_PTR
)lpszClass
), &SectionName
))
110 ERR("Couldn't get atom name for atom %x !\n", LOWORD((DWORD_PTR
)lpszClass
));
113 SectionName
.Length
= wcslen(SectionNameBuf
) * sizeof(WCHAR
);
114 TRACE("ClassNameToVersion got name %wZ from atom\n", &SectionName
);
120 ANSI_STRING AnsiString
;
121 RtlInitAnsiString(&AnsiString
, lpszClass
);
122 RtlInitEmptyUnicodeString(&SectionName
, SectionNameBuf
, sizeof(SectionNameBuf
));
123 RtlAnsiStringToUnicodeString(&SectionName
, &AnsiString
, FALSE
);
127 RtlInitUnicodeString(&SectionName
, lpszClass
);
130 Status
= RtlFindActivationContextSectionString( FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX
,
132 ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION
,
136 #ifdef USE_VERSIONED_CLASSES
137 if (NT_SUCCESS(Status
) && KeyedData
.ulDataFormatVersion
== 1)
139 struct strsection_header
*SectionHeader
= KeyedData
.lpSectionBase
;
141 /* Find activation context */
142 if(SectionHeader
&& SectionHeader
->count
> 0)
144 struct wndclass_redirect_data
*WindowRedirectionData
= KeyedData
.lpData
;
145 if(WindowRedirectionData
&& WindowRedirectionData
->module_len
)
147 LPCWSTR lpLibFileName
;
149 VersionedClass
= (WCHAR
*)((BYTE
*)WindowRedirectionData
+ WindowRedirectionData
->name_offset
);
150 lpLibFileName
= (WCHAR
*)((BYTE
*)KeyedData
.lpSectionBase
+ WindowRedirectionData
->module_offset
);
151 TRACE("Returning VersionedClass=%S, plpLibFileName=%S for class %S\n", VersionedClass
, lpLibFileName
, SectionName
.Buffer
);
153 if (pContext
) *pContext
= KeyedData
.hActCtx
;
154 if (plpLibFileName
) *plpLibFileName
= lpLibFileName
;
160 if (KeyedData
.hActCtx
)
161 RtlReleaseActivationContext(KeyedData
.hActCtx
);
164 #ifndef DEFAULT_ACTIVATION_CONTEXTS_SUPPORTED
165 /* This block is a hack! */
169 * In windows the default activation context always contains comctl32v5
170 * In reactos we don't have a default activation context so we
173 VersionedClass
= is_comctl32_class(SectionName
.Buffer
);
176 if (pContext
) *pContext
= 0;
177 if (plpLibFileName
) *plpLibFileName
= L
"comctl32";
183 * The returned strings are pointers in the activation context and
184 * will get freed when the activation context gets freed
186 return VersionedClass
;
190 // Ref: http://yvs-it.blogspot.com/2010/04/initcommoncontrolsex.html
194 VersionRegisterClass(
196 LPCWSTR lpLibFileName
,
198 HMODULE
* phLibModule
)
201 HMODULE hLibModule
= NULL
;
202 PREGISTERCLASSNAMEW pRegisterClassNameW
;
203 UNICODE_STRING ClassName
;
204 WCHAR ClassNameBuf
[MAX_PATH
] = {0};
205 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED Frame
= { sizeof(Frame
), 1 };
207 RtlActivateActivationContextUnsafeFast(&Frame
, Contex
);
211 hLibModule
= LoadLibraryW(lpLibFileName
);
214 if ((pRegisterClassNameW
= (void*)GetProcAddress(hLibModule
, "RegisterClassNameW")))
216 if (IS_ATOM(pszClass
))
218 RtlInitEmptyUnicodeString(&ClassName
, ClassNameBuf
, sizeof(ClassNameBuf
));
219 if (!NtUserGetAtomName(LOWORD((DWORD_PTR
)pszClass
), &ClassName
))
221 ERR("Error while verifying ATOM\n");
222 _SEH2_YIELD(goto Error_Exit
);
224 pszClass
= ClassName
.Buffer
;
226 Ret
= pRegisterClassNameW(pszClass
);
230 WARN("No RegisterClassNameW PROC\n");
234 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
240 if (Ret
|| !hLibModule
)
242 if (phLibModule
) *phLibModule
= hLibModule
;
246 DWORD dwLastError
= GetLastError();
247 FreeLibrary(hLibModule
);
248 SetLastError(dwLastError
);
251 RtlDeactivateActivationContextUnsafeFast(&Frame
);
265 UNICODE_STRING ClassName
= {0};
267 HMODULE hLibModule
= NULL
;
269 BOOL Ret
, ClassFound
= FALSE
, ConvertedString
= FALSE
;
270 LPCWSTR lpszClsVersion
;
272 LPCWSTR lpLibFileName
= NULL
;
274 TRACE("%p class/atom: %s/%04x %p\n", hInstance
,
275 IS_ATOM(lpszClass
) ? NULL
: lpszClass
,
276 IS_ATOM(lpszClass
) ? lpszClass
: 0,
281 SetLastError(ERROR_NOACCESS
);
285 if (hInstance
== User32Instance
)
290 if (lpszClass
== NULL
)
292 SetLastError(ERROR_INVALID_PARAMETER
);
296 lpszClsVersion
= ClassNameToVersion(lpszClass
, NULL
, &lpLibFileName
, &pCtx
, TRUE
);
299 RtlInitUnicodeString(&ClassName
, lpszClsVersion
);
301 else if (IS_ATOM(lpszClass
))
303 ClassName
.Buffer
= (PWSTR
)((ULONG_PTR
)lpszClass
);
307 ConvertedString
= TRUE
;
308 if (!RtlCreateUnicodeStringFromAsciiz(&ClassName
, lpszClass
))
310 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
315 if (!RegisterDefaultClasses
)
317 TRACE("RegisterSystemControls\n");
318 RegisterSystemControls();
323 Ret
= NtUserGetClassInfo(hInstance
,
325 (LPWNDCLASSEXW
)lpwcx
,
326 (LPWSTR
*)&pszMenuName
,
329 if (!lpLibFileName
) break;
332 dwLastError
= GetLastError();
333 if ( dwLastError
== ERROR_CANNOT_FIND_WND_CLASS
||
334 dwLastError
== ERROR_CLASS_DOES_NOT_EXIST
)
336 ClassFound
= VersionRegisterClass(ClassName
.Buffer
, lpLibFileName
, pCtx
, &hLibModule
);
337 if (ClassFound
) continue;
342 dwLastError
= GetLastError();
343 FreeLibrary(hLibModule
);
344 SetLastError(dwLastError
);
352 lpwcx
->lpszClassName
= lpszClass
;
353 // lpwcx->lpszMenuName = pszMenuName;
358 RtlFreeUnicodeString(&ClassName
);
375 UNICODE_STRING ClassName
= {0};
377 HMODULE hLibModule
= NULL
;
379 BOOL Ret
, ClassFound
= FALSE
;
380 LPCWSTR lpszClsVersion
;
382 LPCWSTR lpLibFileName
= NULL
;
384 TRACE("%p class/atom: %S/%04x %p\n", hInstance
,
385 IS_ATOM(lpszClass
) ? NULL
: lpszClass
,
386 IS_ATOM(lpszClass
) ? lpszClass
: 0,
389 /* From wine, for speed only, ReactOS supports the correct return in
390 * Win32k. cbSize is ignored.
394 SetLastError( ERROR_NOACCESS
);
398 if (hInstance
== User32Instance
)
403 if (lpszClass
== NULL
)
405 SetLastError(ERROR_INVALID_PARAMETER
);
409 lpszClsVersion
= ClassNameToVersion(lpszClass
, NULL
, &lpLibFileName
, &pCtx
, FALSE
);
412 RtlInitUnicodeString(&ClassName
, lpszClsVersion
);
414 else if (IS_ATOM(lpszClass
))
416 ClassName
.Buffer
= (PWSTR
)((ULONG_PTR
)lpszClass
);
420 RtlInitUnicodeString(&ClassName
, lpszClass
);
423 if (!RegisterDefaultClasses
)
425 TRACE("RegisterSystemControls\n");
426 RegisterSystemControls();
431 Ret
= NtUserGetClassInfo( hInstance
,
437 if (!lpLibFileName
) break;
440 dwLastError
= GetLastError();
441 if ( dwLastError
== ERROR_CANNOT_FIND_WND_CLASS
||
442 dwLastError
== ERROR_CLASS_DOES_NOT_EXIST
)
444 ClassFound
= VersionRegisterClass(ClassName
.Buffer
, lpLibFileName
, pCtx
, &hLibModule
);
445 if (ClassFound
) continue;
450 dwLastError
= GetLastError();
451 FreeLibrary(hLibModule
);
452 SetLastError(dwLastError
);
460 lpwcx
->lpszClassName
= lpszClass
;
461 // lpwcx->lpszMenuName = pszMenuName;
475 LPWNDCLASSA lpWndClass
)
480 retval
= GetClassInfoExA(hInstance
, lpClassName
, &wcex
);
483 lpWndClass
->style
= wcex
.style
;
484 lpWndClass
->lpfnWndProc
= wcex
.lpfnWndProc
;
485 lpWndClass
->cbClsExtra
= wcex
.cbClsExtra
;
486 lpWndClass
->cbWndExtra
= wcex
.cbWndExtra
;
487 lpWndClass
->hInstance
= wcex
.hInstance
;
488 lpWndClass
->hIcon
= wcex
.hIcon
;
489 lpWndClass
->hCursor
= wcex
.hCursor
;
490 lpWndClass
->hbrBackground
= wcex
.hbrBackground
;
491 lpWndClass
->lpszMenuName
= wcex
.lpszMenuName
;
492 lpWndClass
->lpszClassName
= wcex
.lpszClassName
;
506 LPWNDCLASSW lpWndClass
)
511 retval
= GetClassInfoExW(hInstance
, lpClassName
, &wcex
);
514 lpWndClass
->style
= wcex
.style
;
515 lpWndClass
->lpfnWndProc
= wcex
.lpfnWndProc
;
516 lpWndClass
->cbClsExtra
= wcex
.cbClsExtra
;
517 lpWndClass
->cbWndExtra
= wcex
.cbWndExtra
;
518 lpWndClass
->hInstance
= wcex
.hInstance
;
519 lpWndClass
->hIcon
= wcex
.hIcon
;
520 lpWndClass
->hCursor
= wcex
.hCursor
;
521 lpWndClass
->hbrBackground
= wcex
.hbrBackground
;
522 lpWndClass
->lpszMenuName
= wcex
.lpszMenuName
;
523 lpWndClass
->lpszClassName
= wcex
.lpszClassName
;
529 // Based on find_winproc... Fixes many whine tests......
532 IntGetClsWndProc(PWND pWnd
, PCLS Class
, BOOL Ansi
)
535 ULONG_PTR gcpd
, Ret
= 0;
536 // If server side, sweep through proc list and return the client side proc.
537 if (Class
->CSF_flags
& CSF_SERVERSIDEPROC
)
538 { // Always scan through the list due to wine class "deftest".
539 for ( i
= FNID_FIRST
; i
<= FNID_SWITCH
; i
++)
541 if (GETPFNSERVER(i
) == Class
->lpfnWndProc
)
544 Ret
= (ULONG_PTR
)GETPFNCLIENTA(i
);
546 Ret
= (ULONG_PTR
)GETPFNCLIENTW(i
);
552 Ret
= (ULONG_PTR
)Class
->lpfnWndProc
;
553 // Return the proc if one of the FnId default class type.
554 if (Class
->fnid
<= FNID_GHOST
&& Class
->fnid
>= FNID_BUTTON
)
557 { // If match return the right proc by type.
558 if (GETPFNCLIENTW(Class
->fnid
) == Class
->lpfnWndProc
)
559 Ret
= (ULONG_PTR
)GETPFNCLIENTA(Class
->fnid
);
563 if (GETPFNCLIENTA(Class
->fnid
) == Class
->lpfnWndProc
)
564 Ret
= (ULONG_PTR
)GETPFNCLIENTW(Class
->fnid
);
567 // Return on change or Ansi/Unicode proc equal.
568 if ( Ret
!= (ULONG_PTR
)Class
->lpfnWndProc
||
569 Ansi
== !!(Class
->CSF_flags
& CSF_ANSIPROC
) )
572 /* We have an Ansi and Unicode swap! If Ansi create Unicode proc handle.
573 This will force CallWindowProc to deal with it. */
574 gcpd
= NtUserGetCPD( UserHMGetHandle(pWnd
),
575 (Ansi
? UserGetCPDA2U
: UserGetCPDU2A
)|UserGetCPDWndtoCls
,
578 return (gcpd
? gcpd
: Ret
);
582 // Based on IntGetClsWndProc
585 IntGetWndProc(PWND pWnd
, BOOL Ansi
)
588 WNDPROC gcpd
, Ret
= 0;
589 PCLS Class
= DesktopPtrToUser(pWnd
->pcls
);
591 if (!Class
) return Ret
;
593 if (pWnd
->state
& WNDS_SERVERSIDEWINDOWPROC
)
595 for ( i
= FNID_FIRST
; i
<= FNID_SWITCH
; i
++)
597 if (GETPFNSERVER(i
) == pWnd
->lpfnWndProc
)
600 Ret
= GETPFNCLIENTA(i
);
602 Ret
= GETPFNCLIENTW(i
);
608 /* Edit controls are special - they return a wndproc handle when
609 GetWindowLongPtr is called with a different A/W.
610 On the other hand there is no W->A->W conversion so this control
611 is treated specially.
613 if (Class
->fnid
== FNID_EDIT
)
614 Ret
= pWnd
->lpfnWndProc
;
618 Ret
= pWnd
->lpfnWndProc
;
620 if (Class
->fnid
<= FNID_GHOST
&& Class
->fnid
>= FNID_BUTTON
)
624 if (GETPFNCLIENTW(Class
->fnid
) == pWnd
->lpfnWndProc
)
625 Ret
= GETPFNCLIENTA(Class
->fnid
);
629 if (GETPFNCLIENTA(Class
->fnid
) == pWnd
->lpfnWndProc
)
630 Ret
= GETPFNCLIENTW(Class
->fnid
);
633 // Return on the change.
634 if ( Ret
!= pWnd
->lpfnWndProc
)
638 if ( Ansi
== !!(pWnd
->state
& WNDS_ANSIWINDOWPROC
) )
641 gcpd
= (WNDPROC
)NtUserGetCPD( UserHMGetHandle(pWnd
),
642 (Ansi
? UserGetCPDA2U
: UserGetCPDU2A
)|UserGetCPDWindow
,
645 return (gcpd
? gcpd
: Ret
);
648 static ULONG_PTR FASTCALL
649 IntGetClassLongA(PWND Wnd
, PCLS Class
, int nIndex
)
655 if (nIndex
+ sizeof(ULONG_PTR
) < nIndex
||
656 nIndex
+ sizeof(ULONG_PTR
) > Class
->cbclsExtra
)
658 SetLastError(ERROR_INVALID_PARAMETER
);
661 Ret
= *(PULONG_PTR
)((ULONG_PTR
)(Class
+ 1) + nIndex
);
668 Ret
= (ULONG_PTR
)Class
->cbwndExtra
;
672 Ret
= (ULONG_PTR
)Class
->cbclsExtra
;
675 case GCL_HBRBACKGROUND
:
676 Ret
= (ULONG_PTR
)Class
->hbrBackground
;
677 if (Ret
!= 0 && Ret
< 0x4000)
678 Ret
= (ULONG_PTR
)GetSysColorBrush((ULONG
)Ret
- 1);
682 //ERR("Cls 0x%x GCL_HMODULE 0x%x\n", Wnd->pcls, Class->hModule);
683 Ret
= (ULONG_PTR
)Class
->hModule
;
687 Ret
= (ULONG_PTR
)Class
->lpszClientAnsiMenuName
;
691 Ret
= (ULONG_PTR
)Class
->style
;
695 Ret
= (ULONG_PTR
)Class
->atomNVClassName
;
699 Ret
= Class
->spcur
? (ULONG_PTR
)((PPROCMARKHEAD
)SharedPtrToUser(Class
->spcur
))->h
: 0;
703 Ret
= Class
->spicn
? (ULONG_PTR
)((PPROCMARKHEAD
)SharedPtrToUser(Class
->spicn
))->h
: 0;
707 Ret
= Class
->spicnSm
? (ULONG_PTR
)((PPROCMARKHEAD
)SharedPtrToUser(Class
->spicnSm
))->h
: 0;
711 Ret
= IntGetClsWndProc(Wnd
, Class
, TRUE
);
715 SetLastError(ERROR_INVALID_INDEX
);
723 static ULONG_PTR FASTCALL
724 IntGetClassLongW (PWND Wnd
, PCLS Class
, int nIndex
)
730 if (nIndex
+ sizeof(ULONG_PTR
) < nIndex
||
731 nIndex
+ sizeof(ULONG_PTR
) > Class
->cbclsExtra
)
733 SetLastError(ERROR_INVALID_PARAMETER
);
736 Ret
= *(PULONG_PTR
)((ULONG_PTR
)(Class
+ 1) + nIndex
);
743 Ret
= (ULONG_PTR
)Class
->cbwndExtra
;
747 Ret
= (ULONG_PTR
)Class
->cbclsExtra
;
750 case GCLP_HBRBACKGROUND
:
751 Ret
= (ULONG_PTR
)Class
->hbrBackground
;
752 if (Ret
!= 0 && Ret
< 0x4000)
753 Ret
= (ULONG_PTR
)GetSysColorBrush((ULONG
)Ret
- 1);
757 Ret
= (ULONG_PTR
)Class
->hModule
;
761 Ret
= (ULONG_PTR
)Class
->lpszClientUnicodeMenuName
;
765 Ret
= (ULONG_PTR
)Class
->style
;
769 Ret
= (ULONG_PTR
)Class
->atomNVClassName
;
773 Ret
= Class
->spcur
? (ULONG_PTR
)((PPROCMARKHEAD
)SharedPtrToUser(Class
->spcur
))->h
: 0;
777 Ret
= Class
->spicn
? (ULONG_PTR
)((PPROCMARKHEAD
)SharedPtrToUser(Class
->spicn
))->h
: 0;
781 Ret
= Class
->spicnSm
? (ULONG_PTR
)((PPROCMARKHEAD
)SharedPtrToUser(Class
->spicnSm
))->h
: 0;
785 Ret
= IntGetClsWndProc(Wnd
, Class
, FALSE
);
789 SetLastError(ERROR_INVALID_INDEX
);
801 GetClassLongA(HWND hWnd
, int nIndex
)
807 TRACE("%p %d\n", hWnd
, nIndex
);
809 Wnd
= ValidateHwnd(hWnd
);
815 Class
= DesktopPtrToUser(Wnd
->pcls
);
821 case GCLP_HBRBACKGROUND
:
828 SetLastError(ERROR_INVALID_INDEX
);
832 Ret
= IntGetClassLongA(Wnd
, Class
, nIndex
);
836 Ret
= IntGetClassLongA(Wnd
, Class
, nIndex
);
841 WARN("Invalid class for hwnd 0x%p!\n", hWnd
);
844 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
857 GetClassLongW ( HWND hWnd
, int nIndex
)
863 TRACE("%p %d\n", hWnd
, nIndex
);
865 Wnd
= ValidateHwnd(hWnd
);
871 Class
= DesktopPtrToUser(Wnd
->pcls
);
877 case GCLP_HBRBACKGROUND
:
884 SetLastError(ERROR_INVALID_INDEX
);
888 Ret
= IntGetClassLongW(Wnd
, Class
, nIndex
);
892 Ret
= IntGetClassLongW(Wnd
, Class
, nIndex
);
897 WARN("Invalid class for hwnd 0x%p!\n", hWnd
);
900 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
915 GetClassLongPtrA(HWND hWnd
,
922 TRACE("%p %d\n", hWnd
, nIndex
);
924 Wnd
= ValidateHwnd(hWnd
);
930 Class
= DesktopPtrToUser(Wnd
->pcls
);
933 Ret
= IntGetClassLongA(Wnd
, Class
, nIndex
);
937 WARN("Invalid class for hwnd 0x%p!\n", hWnd
);
940 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
954 GetClassLongPtrW(HWND hWnd
,
961 TRACE("%p %d\n", hWnd
, nIndex
);
963 Wnd
= ValidateHwnd(hWnd
);
969 Class
= DesktopPtrToUser(Wnd
->pcls
);
972 Ret
= IntGetClassLongW(Wnd
, Class
, nIndex
);
976 WARN("Invalid class for hwnd 0x%p!\n", hWnd
);
979 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
999 WCHAR tmpbuf
[MAX_ATOM_LEN
+ 1];
1002 if (nMaxCount
<= 0) return 0;
1003 if (!GetClassNameW( hWnd
, tmpbuf
, sizeof(tmpbuf
)/sizeof(WCHAR
) )) return 0;
1004 RtlUnicodeToMultiByteN( lpClassName
, nMaxCount
- 1, (PULONG
)&len
, tmpbuf
, strlenW(tmpbuf
) * sizeof(WCHAR
) );
1005 lpClassName
[len
] = 0;
1007 TRACE("%p class/atom: %s/%04x %x\n", hWnd
,
1008 IS_ATOM(lpClassName
) ? NULL
: lpClassName
,
1009 IS_ATOM(lpClassName
) ? lpClassName
: 0,
1026 UNICODE_STRING ClassName
;
1029 RtlInitEmptyUnicodeString(&ClassName
,
1031 nMaxCount
* sizeof(WCHAR
));
1033 Result
= NtUserGetClassName(hWnd
,
1037 TRACE("%p class/atom: %S/%04x %x\n", hWnd
,
1038 IS_ATOM(lpClassName
) ? NULL
: lpClassName
,
1039 IS_ATOM(lpClassName
) ? lpClassName
: 0,
1059 if (offset
< 0) return GetClassLongA( hwnd
, offset
);
1061 Wnd
= ValidateHwnd(hwnd
);
1065 class = DesktopPtrToUser(Wnd
->pcls
);
1066 if (class == NULL
) return 0;
1068 if (offset
<= class->cbclsExtra
- sizeof(WORD
))
1069 memcpy( &retvalue
, (char *)(class + 1) + offset
, sizeof(retvalue
) );
1071 SetLastError( ERROR_INVALID_INDEX
);
1077 LONG_PTR
IntGetWindowLong( HWND hwnd
, INT offset
, UINT size
, BOOL unicode
)
1079 LONG_PTR retvalue
= 0;
1082 if (offset
== GWLP_HWNDPARENT
)
1084 HWND parent
= GetAncestor( hwnd
, GA_PARENT
);
1085 if (parent
== GetDesktopWindow()) parent
= GetWindow( hwnd
, GW_OWNER
);
1086 return (ULONG_PTR
)parent
;
1089 if (!(wndPtr
= ValidateHwnd( hwnd
)))
1091 SetLastError( ERROR_INVALID_WINDOW_HANDLE
);
1097 if (offset
> (int)(wndPtr
->cbwndExtra
- size
))
1099 WARN("Invalid offset %d\n", offset
);
1100 SetLastError( ERROR_INVALID_INDEX
);
1103 retvalue
= *((LONG_PTR
*)((PCHAR
)(wndPtr
+ 1) + offset
));
1105 /* WINE: special case for dialog window procedure */
1106 //if ((offset == DWLP_DLGPROC) && (size == sizeof(LONG_PTR)) && (wndPtr->flags & WIN_ISDIALOG))
1107 // retvalue = (LONG_PTR)IntGetWndProc( (WNDPROC)retvalue, unicode );
1113 case GWLP_USERDATA
: retvalue
= wndPtr
->dwUserData
; break;
1114 case GWL_STYLE
: retvalue
= wndPtr
->style
; break;
1115 case GWL_EXSTYLE
: retvalue
= wndPtr
->ExStyle
; break;
1116 case GWLP_ID
: retvalue
= wndPtr
->IDMenu
; break;
1117 case GWLP_HINSTANCE
: retvalue
= (ULONG_PTR
)wndPtr
->hModule
; break;
1120 if (!TestWindowProcess(wndPtr
))
1122 SetLastError(ERROR_ACCESS_DENIED
);
1125 retvalue
= (ULONG_PTR
)IntGetWndProc(wndPtr
, !unicode
);
1129 WARN("Unknown offset %d\n", offset
);
1130 SetLastError( ERROR_INVALID_INDEX
);
1141 GetWindowLongA ( HWND hWnd
, int nIndex
)
1143 return IntGetWindowLong( hWnd
, nIndex
, sizeof(LONG
), FALSE
);
1151 GetWindowLongW(HWND hWnd
, int nIndex
)
1153 return IntGetWindowLong( hWnd
, nIndex
, sizeof(LONG
), TRUE
);
1162 GetWindowLongPtrA(HWND hWnd
,
1165 return IntGetWindowLong( hWnd
, nIndex
, sizeof(LONG_PTR
), FALSE
);
1173 GetWindowLongPtrW(HWND hWnd
,
1176 return IntGetWindowLong( hWnd
, nIndex
, sizeof(LONG_PTR
), TRUE
);
1186 GetWindowWord(HWND hWnd
, int nIndex
)
1191 case GWLP_HINSTANCE
:
1192 case GWLP_HWNDPARENT
:
1197 WARN("Invalid offset %d\n", nIndex
);
1198 SetLastError( ERROR_INVALID_INDEX
);
1203 return IntGetWindowLong( hWnd
, nIndex
, sizeof(WORD
), FALSE
);
1211 RealGetWindowClassW(
1216 UNICODE_STRING ClassName
;
1218 RtlInitEmptyUnicodeString(&ClassName
,
1220 cchType
* sizeof(WCHAR
));
1222 return NtUserGetClassName(hwnd
,TRUE
,&ClassName
);
1231 RealGetWindowClassA(
1236 WCHAR tmpbuf
[MAX_ATOM_LEN
+ 1];
1239 if ((INT
)cchType
<= 0) return 0;
1240 if (!RealGetWindowClassW( hwnd
, tmpbuf
, sizeof(tmpbuf
)/sizeof(WCHAR
) )) return 0;
1241 RtlUnicodeToMultiByteN( pszType
, cchType
- 1, (PULONG
)&len
, tmpbuf
, strlenW(tmpbuf
) * sizeof(WCHAR
) );
1247 * Create a small icon based on a standard icon
1249 #if 0 // Keep vintage code from revision 18764 by GvG!
1251 CreateSmallIcon(HICON StdIcon
)
1253 HICON SmallIcon
= NULL
;
1256 int SmallIconHeight
;
1257 BITMAP StdBitmapInfo
;
1258 HDC hSourceDc
= NULL
;
1261 HBITMAP OldSourceBitmap
= NULL
;
1262 HBITMAP OldDestBitmap
= NULL
;
1264 SmallInfo
.hbmColor
= NULL
;
1265 SmallInfo
.hbmMask
= NULL
;
1267 /* We need something to work with... */
1268 if (NULL
== StdIcon
)
1273 SmallIconWidth
= GetSystemMetrics(SM_CXSMICON
);
1274 SmallIconHeight
= GetSystemMetrics(SM_CYSMICON
);
1275 if (! GetIconInfo(StdIcon
, &StdInfo
))
1277 ERR("Failed to get icon info for icon 0x%x\n", StdIcon
);
1280 if (! GetObjectW(StdInfo
.hbmMask
, sizeof(BITMAP
), &StdBitmapInfo
))
1282 ERR("Failed to get bitmap info for icon 0x%x bitmap 0x%x\n",
1283 StdIcon
, StdInfo
.hbmColor
);
1286 if (StdBitmapInfo
.bmWidth
== SmallIconWidth
&&
1287 StdBitmapInfo
.bmHeight
== SmallIconHeight
)
1289 /* Icon already has the correct dimensions */
1293 hSourceDc
= CreateCompatibleDC(NULL
);
1294 if (NULL
== hSourceDc
)
1296 ERR("Failed to create source DC\n");
1299 hDestDc
= CreateCompatibleDC(NULL
);
1300 if (NULL
== hDestDc
)
1302 ERR("Failed to create dest DC\n");
1306 OldSourceBitmap
= SelectObject(hSourceDc
, StdInfo
.hbmColor
);
1307 if (NULL
== OldSourceBitmap
)
1309 ERR("Failed to select source color bitmap\n");
1312 SmallInfo
.hbmColor
= CreateCompatibleBitmap(hSourceDc
, SmallIconWidth
,
1314 if (NULL
== SmallInfo
.hbmColor
)
1316 ERR("Failed to create color bitmap\n");
1319 OldDestBitmap
= SelectObject(hDestDc
, SmallInfo
.hbmColor
);
1320 if (NULL
== OldDestBitmap
)
1322 ERR("Failed to select dest color bitmap\n");
1325 if (! StretchBlt(hDestDc
, 0, 0, SmallIconWidth
, SmallIconHeight
,
1326 hSourceDc
, 0, 0, StdBitmapInfo
.bmWidth
,
1327 StdBitmapInfo
.bmHeight
, SRCCOPY
))
1329 ERR("Failed to stretch color bitmap\n");
1333 if (NULL
== SelectObject(hSourceDc
, StdInfo
.hbmMask
))
1335 ERR("Failed to select source mask bitmap\n");
1338 SmallInfo
.hbmMask
= CreateCompatibleBitmap(hSourceDc
, SmallIconWidth
, SmallIconHeight
);
1339 if (NULL
== SmallInfo
.hbmMask
)
1341 ERR("Failed to create mask bitmap\n");
1344 if (NULL
== SelectObject(hDestDc
, SmallInfo
.hbmMask
))
1346 ERR("Failed to select dest mask bitmap\n");
1349 if (! StretchBlt(hDestDc
, 0, 0, SmallIconWidth
, SmallIconHeight
,
1350 hSourceDc
, 0, 0, StdBitmapInfo
.bmWidth
,
1351 StdBitmapInfo
.bmHeight
, SRCCOPY
))
1353 ERR("Failed to stretch mask bitmap\n");
1357 SmallInfo
.fIcon
= TRUE
;
1358 SmallInfo
.xHotspot
= SmallIconWidth
/ 2;
1359 SmallInfo
.yHotspot
= SmallIconHeight
/ 2;
1360 SmallIcon
= CreateIconIndirect(&SmallInfo
);
1361 if (NULL
== SmallIcon
)
1363 ERR("Failed to create icon\n");
1368 if (NULL
!= SmallInfo
.hbmMask
)
1370 DeleteObject(SmallInfo
.hbmMask
);
1372 if (NULL
!= OldDestBitmap
)
1374 SelectObject(hDestDc
, OldDestBitmap
);
1376 if (NULL
!= SmallInfo
.hbmColor
)
1378 DeleteObject(SmallInfo
.hbmColor
);
1380 if (NULL
!= hDestDc
)
1384 if (NULL
!= OldSourceBitmap
)
1386 SelectObject(hSourceDc
, OldSourceBitmap
);
1388 if (NULL
!= hSourceDc
)
1390 DeleteDC(hSourceDc
);
1398 RegisterClassExWOWW(WNDCLASSEXW
*lpwcx
,
1405 WNDCLASSEXW WndClass
;
1406 UNICODE_STRING ClassName
;
1407 UNICODE_STRING ClassVersion
;
1408 UNICODE_STRING MenuName
= {0};
1409 CLSMENUNAME clsMenuName
;
1410 ANSI_STRING AnsiMenuName
;
1411 LPCWSTR lpszClsVersion
;
1413 if (lpwcx
== NULL
|| lpwcx
->cbSize
!= sizeof(WNDCLASSEXW
) ||
1414 lpwcx
->cbClsExtra
< 0 || lpwcx
->cbWndExtra
< 0 ||
1415 lpwcx
->lpszClassName
== NULL
)
1417 TRACE("RegisterClassExWOWW Invalid Parameter Error!\n");
1418 SetLastError(ERROR_INVALID_PARAMETER
);
1424 if (!RegisterDefaultClasses
) RegisterSystemControls();
1427 * On real Windows this looks more like:
1428 * if (lpwcx->hInstance == User32Instance &&
1429 * *(PULONG)((ULONG_PTR)NtCurrentTeb() + 0x6D4) & 0x400)
1430 * But since I have no idea what the magic field in the
1431 * TEB structure means, I rather decided to omit that.
1434 GetWin32ClientInfo()->dwExpWinVer & (WINVER == 0x400)
1436 if (lpwcx
->hInstance
== User32Instance
)
1438 TRACE("RegisterClassExWOWW User32Instance!\n");
1439 SetLastError(ERROR_INVALID_PARAMETER
);
1442 /* Yes, this is correct. We should modify the passed structure. */
1443 if (lpwcx
->hInstance
== NULL
)
1444 ((WNDCLASSEXW
*)lpwcx
)->hInstance
= GetModuleHandleW(NULL
);
1446 RtlCopyMemory(&WndClass
, lpwcx
, sizeof(WNDCLASSEXW
));
1448 if (NULL == WndClass.hIconSm)
1450 WndClass.hIconSm = CreateSmallIcon(WndClass.hIcon);
1453 RtlInitEmptyAnsiString(&AnsiMenuName
, NULL
, 0);
1454 if (WndClass
.lpszMenuName
!= NULL
)
1456 if (!IS_INTRESOURCE(WndClass
.lpszMenuName
))
1458 if (WndClass
.lpszMenuName
[0])
1460 RtlInitUnicodeString(&MenuName
, WndClass
.lpszMenuName
);
1461 RtlUnicodeStringToAnsiString( &AnsiMenuName
, &MenuName
, TRUE
);
1466 MenuName
.Buffer
= (LPWSTR
)WndClass
.lpszMenuName
;
1467 AnsiMenuName
.Buffer
= (PCHAR
)WndClass
.lpszMenuName
;
1471 if (IS_ATOM(WndClass
.lpszClassName
))
1474 ClassName
.MaximumLength
= 0;
1475 ClassName
.Buffer
= (LPWSTR
)WndClass
.lpszClassName
;
1479 RtlInitUnicodeString(&ClassName
, WndClass
.lpszClassName
);
1482 ClassVersion
= ClassName
;
1485 lpszClsVersion
= ClassNameToVersion(lpwcx
->lpszClassName
, NULL
, NULL
, NULL
, FALSE
);
1488 RtlInitUnicodeString(&ClassVersion
, lpszClsVersion
);
1492 clsMenuName
.pszClientAnsiMenuName
= AnsiMenuName
.Buffer
;
1493 clsMenuName
.pwszClientUnicodeMenuName
= MenuName
.Buffer
;
1494 clsMenuName
.pusMenuName
= &MenuName
;
1496 Atom
= NtUserRegisterClassExWOW( &WndClass
,
1504 TRACE("atom=%04x wndproc=%p hinst=%p bg=%p style=%08x clsExt=%d winExt=%d class=%p\n",
1505 Atom
, lpwcx
->lpfnWndProc
, lpwcx
->hInstance
, lpwcx
->hbrBackground
,
1506 lpwcx
->style
, lpwcx
->cbClsExtra
, lpwcx
->cbWndExtra
, WndClass
);
1515 RegisterClassExA(CONST WNDCLASSEXA
*lpwcx
)
1518 WNDCLASSEXW WndClass
;
1519 WCHAR mname
[MAX_BUFFER_LEN
];
1520 WCHAR cname
[MAX_BUFFER_LEN
];
1522 RtlCopyMemory(&WndClass
, lpwcx
, sizeof(WNDCLASSEXA
));
1524 if (WndClass
.lpszMenuName
!= NULL
)
1526 if (!IS_INTRESOURCE(WndClass
.lpszMenuName
))
1528 if (WndClass
.lpszMenuName
[0])
1530 if (!MultiByteToWideChar( CP_ACP
, 0, lpwcx
->lpszMenuName
, -1, mname
, MAX_ATOM_LEN
+ 1 )) return 0;
1532 WndClass
.lpszMenuName
= mname
;
1537 if (!IS_ATOM(WndClass
.lpszClassName
))
1539 if (!MultiByteToWideChar( CP_ACP
, 0, lpwcx
->lpszClassName
, -1, cname
, MAX_ATOM_LEN
+ 1 )) return 0;
1541 WndClass
.lpszClassName
= cname
;
1544 Atom
= RegisterClassExWOWW( &WndClass
,
1550 TRACE("A atom=%04x wndproc=%p hinst=%p bg=%p style=%08x clsExt=%d winExt=%d class=%p\n",
1551 Atom
, lpwcx
->lpfnWndProc
, lpwcx
->hInstance
, lpwcx
->hbrBackground
,
1552 lpwcx
->style
, lpwcx
->cbClsExtra
, lpwcx
->cbWndExtra
, WndClass
);
1561 RegisterClassExW(CONST WNDCLASSEXW
*lpwcx
)
1565 Atom
= RegisterClassExWOWW( (WNDCLASSEXW
*)lpwcx
, 0, 0, 0, TRUE
);
1567 TRACE("W atom=%04x wndproc=%p hinst=%p bg=%p style=%08x clsExt=%d winExt=%d\n",
1568 Atom
, lpwcx
->lpfnWndProc
, lpwcx
->hInstance
, lpwcx
->hbrBackground
,
1569 lpwcx
->style
, lpwcx
->cbClsExtra
, lpwcx
->cbWndExtra
);
1578 RegisterClassA(CONST WNDCLASSA
*lpWndClass
)
1582 if (lpWndClass
== NULL
)
1585 RtlCopyMemory(&Class
.style
, lpWndClass
, sizeof(WNDCLASSA
));
1586 Class
.cbSize
= sizeof(WNDCLASSEXA
);
1587 Class
.hIconSm
= NULL
;
1589 return RegisterClassExA(&Class
);
1596 RegisterClassW(CONST WNDCLASSW
*lpWndClass
)
1600 if (lpWndClass
== NULL
)
1603 RtlCopyMemory(&Class
.style
, lpWndClass
, sizeof(WNDCLASSW
));
1604 Class
.cbSize
= sizeof(WNDCLASSEXW
);
1605 Class
.hIconSm
= NULL
;
1607 return RegisterClassExW(&Class
);
1615 SetClassLongA (HWND hWnd
,
1619 PSTR lpStr
= (PSTR
)(ULONG_PTR
)dwNewLong
;
1620 UNICODE_STRING Value
= {0};
1621 BOOL Allocated
= FALSE
;
1624 /* FIXME - portability!!!! */
1626 if (nIndex
== GCL_MENUNAME
&& lpStr
!= NULL
)
1628 if (!IS_INTRESOURCE(lpStr
))
1630 if (!RtlCreateUnicodeStringFromAsciiz(&Value
,
1633 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1640 Value
.Buffer
= (PWSTR
)lpStr
;
1642 dwNewLong
= (LONG_PTR
)&Value
;
1644 else if (nIndex
== GCW_ATOM
&& lpStr
!= NULL
)
1646 if (!IS_ATOM(lpStr
))
1648 if (!RtlCreateUnicodeStringFromAsciiz(&Value
,
1651 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1658 Value
.Buffer
= (PWSTR
)lpStr
;
1660 dwNewLong
= (LONG_PTR
)&Value
;
1663 Ret
= (DWORD
)NtUserSetClassLong(hWnd
,
1670 RtlFreeUnicodeString(&Value
);
1682 SetClassLongW(HWND hWnd
,
1686 PWSTR lpStr
= (PWSTR
)(ULONG_PTR
)dwNewLong
;
1687 UNICODE_STRING Value
= {0};
1689 TRACE("%p %d %lx\n", hWnd
, nIndex
, dwNewLong
);
1691 /* FIXME - portability!!!! */
1693 if (nIndex
== GCL_MENUNAME
&& lpStr
!= NULL
)
1695 if (!IS_INTRESOURCE(lpStr
))
1697 RtlInitUnicodeString(&Value
,
1701 Value
.Buffer
= lpStr
;
1703 dwNewLong
= (LONG_PTR
)&Value
;
1705 else if (nIndex
== GCW_ATOM
&& lpStr
!= NULL
)
1707 if (!IS_ATOM(lpStr
))
1709 RtlInitUnicodeString(&Value
,
1713 Value
.Buffer
= lpStr
;
1715 dwNewLong
= (LONG_PTR
)&Value
;
1718 return (DWORD
)NtUserSetClassLong(hWnd
,
1730 SetClassLongPtrA(HWND hWnd
,
1743 SetClassLongPtrW(HWND hWnd
,
1762 * NOTE: Obsoleted in 32-bit windows
1765 if ((nIndex
< 0) && (nIndex
!= GCW_ATOM
))
1768 return (WORD
) SetClassLongW ( hWnd
, nIndex
, wNewWord
);
1776 SetWindowWord ( HWND hWnd
,int nIndex
,WORD wNewWord
)
1781 case GWLP_HINSTANCE
:
1782 case GWLP_HWNDPARENT
:
1787 WARN("Invalid offset %d\n", nIndex
);
1788 SetLastError( ERROR_INVALID_INDEX
);
1793 return NtUserSetWindowLong( hWnd
, nIndex
, wNewWord
, FALSE
);
1807 return NtUserSetWindowLong(hWnd
, nIndex
, dwNewLong
, TRUE
);
1820 return NtUserSetWindowLong(hWnd
, nIndex
, dwNewLong
, FALSE
);
1829 SetWindowLongPtrA(HWND hWnd
,
1833 return NtUserSetWindowLong(hWnd
, nIndex
, dwNewLong
, FALSE
);
1841 SetWindowLongPtrW(HWND hWnd
,
1845 return NtUserSetWindowLong(hWnd
, nIndex
, dwNewLong
, FALSE
);
1856 HINSTANCE hInstance
)
1858 UNICODE_STRING ClassName
= {0};
1860 LPCWSTR lpszClsVersion
;
1861 BOOL ConvertedString
= FALSE
;
1863 TRACE("class/atom: %s/%04x %p\n",
1864 IS_ATOM(lpClassName
) ? NULL
: lpClassName
,
1865 IS_ATOM(lpClassName
) ? lpClassName
: 0,
1868 lpszClsVersion
= ClassNameToVersion(lpClassName
, NULL
, NULL
, NULL
, TRUE
);
1871 RtlInitUnicodeString(&ClassName
, lpszClsVersion
);
1873 else if (!IS_ATOM(lpClassName
))
1875 ConvertedString
= TRUE
;
1876 if (!RtlCreateUnicodeStringFromAsciiz(&ClassName
, lpClassName
))
1878 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1884 ClassName
.Buffer
= (PWSTR
)((ULONG_PTR
)lpClassName
);
1887 Ret
= NtUserUnregisterClass(&ClassName
, hInstance
, 0);
1889 if (ConvertedString
)
1890 RtlFreeUnicodeString(&ClassName
);
1902 LPCWSTR lpClassName
,
1903 HINSTANCE hInstance
)
1905 UNICODE_STRING ClassName
= {0};
1906 LPCWSTR lpszClsVersion
;
1908 TRACE("class/atom: %S/%04x %p\n",
1909 IS_ATOM(lpClassName
) ? NULL
: lpClassName
,
1910 IS_ATOM(lpClassName
) ? lpClassName
: 0,
1913 lpszClsVersion
= ClassNameToVersion(lpClassName
, NULL
, NULL
, NULL
, FALSE
);
1916 RtlInitUnicodeString(&ClassName
, lpszClsVersion
);
1918 else if (!IS_ATOM(lpClassName
))
1920 RtlInitUnicodeString(&ClassName
, lpClassName
);
1924 ClassName
.Buffer
= (PWSTR
)((ULONG_PTR
)lpClassName
);
1927 return NtUserUnregisterClass(&ClassName
, hInstance
, 0);