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 ERR("VersionRegisterClass: Attempting to call RegisterClassNameW in %S\n.", lpLibFileName
);
209 RtlActivateActivationContextUnsafeFast(&Frame
, Contex
);
213 hLibModule
= LoadLibraryW(lpLibFileName
);
216 if ((pRegisterClassNameW
= (void*)GetProcAddress(hLibModule
, "RegisterClassNameW")))
218 if (IS_ATOM(pszClass
))
220 RtlInitEmptyUnicodeString(&ClassName
, ClassNameBuf
, sizeof(ClassNameBuf
));
221 if (!NtUserGetAtomName(LOWORD((DWORD_PTR
)pszClass
), &ClassName
))
223 ERR("Error while verifying ATOM\n");
224 _SEH2_YIELD(goto Error_Exit
);
226 pszClass
= ClassName
.Buffer
;
228 Ret
= pRegisterClassNameW(pszClass
);
232 WARN("No RegisterClassNameW PROC\n");
236 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
242 if (Ret
|| !hLibModule
)
244 if (phLibModule
) *phLibModule
= hLibModule
;
248 DWORD dwLastError
= GetLastError();
249 FreeLibrary(hLibModule
);
250 SetLastError(dwLastError
);
253 RtlDeactivateActivationContextUnsafeFast(&Frame
);
267 UNICODE_STRING ClassName
= {0};
269 HMODULE hLibModule
= NULL
;
271 BOOL Ret
, ClassFound
= FALSE
, ConvertedString
= FALSE
;
272 LPCWSTR lpszClsVersion
;
274 LPCWSTR lpLibFileName
= NULL
;
276 TRACE("%p class/atom: %s/%04x %p\n", hInstance
,
277 IS_ATOM(lpszClass
) ? NULL
: lpszClass
,
278 IS_ATOM(lpszClass
) ? lpszClass
: 0,
283 SetLastError(ERROR_NOACCESS
);
287 if (hInstance
== User32Instance
)
292 if (lpszClass
== NULL
)
294 SetLastError(ERROR_INVALID_PARAMETER
);
298 lpszClsVersion
= ClassNameToVersion(lpszClass
, NULL
, &lpLibFileName
, &pCtx
, TRUE
);
301 RtlInitUnicodeString(&ClassName
, lpszClsVersion
);
303 else if (IS_ATOM(lpszClass
))
305 ClassName
.Buffer
= (PWSTR
)((ULONG_PTR
)lpszClass
);
309 ConvertedString
= TRUE
;
310 if (!RtlCreateUnicodeStringFromAsciiz(&ClassName
, lpszClass
))
312 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
317 if (!RegisterDefaultClasses
)
319 TRACE("RegisterSystemControls\n");
320 RegisterSystemControls();
325 Ret
= NtUserGetClassInfo(hInstance
,
327 (LPWNDCLASSEXW
)lpwcx
,
328 (LPWSTR
*)&pszMenuName
,
331 if (!lpLibFileName
) break;
334 dwLastError
= GetLastError();
335 if ( dwLastError
== ERROR_CANNOT_FIND_WND_CLASS
||
336 dwLastError
== ERROR_CLASS_DOES_NOT_EXIST
)
338 ClassFound
= VersionRegisterClass(ClassName
.Buffer
, lpLibFileName
, pCtx
, &hLibModule
);
339 if (ClassFound
) continue;
344 dwLastError
= GetLastError();
345 FreeLibrary(hLibModule
);
346 SetLastError(dwLastError
);
354 lpwcx
->lpszClassName
= lpszClass
;
355 // lpwcx->lpszMenuName = pszMenuName;
360 RtlFreeUnicodeString(&ClassName
);
377 UNICODE_STRING ClassName
= {0};
379 HMODULE hLibModule
= NULL
;
381 BOOL Ret
, ClassFound
= FALSE
;
382 LPCWSTR lpszClsVersion
;
384 LPCWSTR lpLibFileName
= NULL
;
386 TRACE("%p class/atom: %S/%04x %p\n", hInstance
,
387 IS_ATOM(lpszClass
) ? NULL
: lpszClass
,
388 IS_ATOM(lpszClass
) ? lpszClass
: 0,
391 /* From wine, for speed only, ReactOS supports the correct return in
392 * Win32k. cbSize is ignored.
396 SetLastError( ERROR_NOACCESS
);
400 if (hInstance
== User32Instance
)
405 if (lpszClass
== NULL
)
407 SetLastError(ERROR_INVALID_PARAMETER
);
411 lpszClsVersion
= ClassNameToVersion(lpszClass
, NULL
, &lpLibFileName
, &pCtx
, FALSE
);
414 RtlInitUnicodeString(&ClassName
, lpszClsVersion
);
416 else if (IS_ATOM(lpszClass
))
418 ClassName
.Buffer
= (PWSTR
)((ULONG_PTR
)lpszClass
);
422 RtlInitUnicodeString(&ClassName
, lpszClass
);
425 if (!RegisterDefaultClasses
)
427 TRACE("RegisterSystemControls\n");
428 RegisterSystemControls();
433 Ret
= NtUserGetClassInfo( hInstance
,
439 if (!lpLibFileName
) break;
442 dwLastError
= GetLastError();
443 if ( dwLastError
== ERROR_CANNOT_FIND_WND_CLASS
||
444 dwLastError
== ERROR_CLASS_DOES_NOT_EXIST
)
446 ClassFound
= VersionRegisterClass(ClassName
.Buffer
, lpLibFileName
, pCtx
, &hLibModule
);
447 if (ClassFound
) continue;
452 dwLastError
= GetLastError();
453 FreeLibrary(hLibModule
);
454 SetLastError(dwLastError
);
462 lpwcx
->lpszClassName
= lpszClass
;
463 // lpwcx->lpszMenuName = pszMenuName;
477 LPWNDCLASSA lpWndClass
)
482 retval
= GetClassInfoExA(hInstance
, lpClassName
, &wcex
);
485 lpWndClass
->style
= wcex
.style
;
486 lpWndClass
->lpfnWndProc
= wcex
.lpfnWndProc
;
487 lpWndClass
->cbClsExtra
= wcex
.cbClsExtra
;
488 lpWndClass
->cbWndExtra
= wcex
.cbWndExtra
;
489 lpWndClass
->hInstance
= wcex
.hInstance
;
490 lpWndClass
->hIcon
= wcex
.hIcon
;
491 lpWndClass
->hCursor
= wcex
.hCursor
;
492 lpWndClass
->hbrBackground
= wcex
.hbrBackground
;
493 lpWndClass
->lpszMenuName
= wcex
.lpszMenuName
;
494 lpWndClass
->lpszClassName
= wcex
.lpszClassName
;
508 LPWNDCLASSW lpWndClass
)
513 retval
= GetClassInfoExW(hInstance
, lpClassName
, &wcex
);
516 lpWndClass
->style
= wcex
.style
;
517 lpWndClass
->lpfnWndProc
= wcex
.lpfnWndProc
;
518 lpWndClass
->cbClsExtra
= wcex
.cbClsExtra
;
519 lpWndClass
->cbWndExtra
= wcex
.cbWndExtra
;
520 lpWndClass
->hInstance
= wcex
.hInstance
;
521 lpWndClass
->hIcon
= wcex
.hIcon
;
522 lpWndClass
->hCursor
= wcex
.hCursor
;
523 lpWndClass
->hbrBackground
= wcex
.hbrBackground
;
524 lpWndClass
->lpszMenuName
= wcex
.lpszMenuName
;
525 lpWndClass
->lpszClassName
= wcex
.lpszClassName
;
531 // Based on find_winproc... Fixes many whine tests......
534 IntGetClsWndProc(PWND pWnd
, PCLS Class
, BOOL Ansi
)
537 ULONG_PTR gcpd
, Ret
= 0;
538 // If server side, sweep through proc list and return the client side proc.
539 if (Class
->CSF_flags
& CSF_SERVERSIDEPROC
)
540 { // Always scan through the list due to wine class "deftest".
541 for ( i
= FNID_FIRST
; i
<= FNID_SWITCH
; i
++)
543 if (GETPFNSERVER(i
) == Class
->lpfnWndProc
)
546 Ret
= (ULONG_PTR
)GETPFNCLIENTA(i
);
548 Ret
= (ULONG_PTR
)GETPFNCLIENTW(i
);
554 Ret
= (ULONG_PTR
)Class
->lpfnWndProc
;
555 // Return the proc if one of the FnId default class type.
556 if (Class
->fnid
<= FNID_GHOST
&& Class
->fnid
>= FNID_BUTTON
)
559 { // If match return the right proc by type.
560 if (GETPFNCLIENTW(Class
->fnid
) == Class
->lpfnWndProc
)
561 Ret
= (ULONG_PTR
)GETPFNCLIENTA(Class
->fnid
);
565 if (GETPFNCLIENTA(Class
->fnid
) == Class
->lpfnWndProc
)
566 Ret
= (ULONG_PTR
)GETPFNCLIENTW(Class
->fnid
);
569 // Return on change or Ansi/Unicode proc equal.
570 if ( Ret
!= (ULONG_PTR
)Class
->lpfnWndProc
||
571 Ansi
== !!(Class
->CSF_flags
& CSF_ANSIPROC
) )
574 /* We have an Ansi and Unicode swap! If Ansi create Unicode proc handle.
575 This will force CallWindowProc to deal with it. */
576 gcpd
= NtUserGetCPD( UserHMGetHandle(pWnd
),
577 (Ansi
? UserGetCPDA2U
: UserGetCPDU2A
)|UserGetCPDWndtoCls
,
580 return (gcpd
? gcpd
: Ret
);
584 // Based on IntGetClsWndProc
587 IntGetWndProc(PWND pWnd
, BOOL Ansi
)
590 WNDPROC gcpd
, Ret
= 0;
591 PCLS Class
= DesktopPtrToUser(pWnd
->pcls
);
593 if (!Class
) return Ret
;
595 if (pWnd
->state
& WNDS_SERVERSIDEWINDOWPROC
)
597 for ( i
= FNID_FIRST
; i
<= FNID_SWITCH
; i
++)
599 if (GETPFNSERVER(i
) == pWnd
->lpfnWndProc
)
602 Ret
= GETPFNCLIENTA(i
);
604 Ret
= GETPFNCLIENTW(i
);
610 /* Edit controls are special - they return a wndproc handle when
611 GetWindowLongPtr is called with a different A/W.
612 On the other hand there is no W->A->W conversion so this control
613 is treated specially.
615 if (Class
->fnid
== FNID_EDIT
)
616 Ret
= pWnd
->lpfnWndProc
;
620 Ret
= pWnd
->lpfnWndProc
;
622 if (Class
->fnid
<= FNID_GHOST
&& Class
->fnid
>= FNID_BUTTON
)
626 if (GETPFNCLIENTW(Class
->fnid
) == pWnd
->lpfnWndProc
)
627 Ret
= GETPFNCLIENTA(Class
->fnid
);
631 if (GETPFNCLIENTA(Class
->fnid
) == pWnd
->lpfnWndProc
)
632 Ret
= GETPFNCLIENTW(Class
->fnid
);
635 // Return on the change.
636 if ( Ret
!= pWnd
->lpfnWndProc
)
640 if ( Ansi
== !!(pWnd
->state
& WNDS_ANSIWINDOWPROC
) )
643 gcpd
= (WNDPROC
)NtUserGetCPD( UserHMGetHandle(pWnd
),
644 (Ansi
? UserGetCPDA2U
: UserGetCPDU2A
)|UserGetCPDWindow
,
647 return (gcpd
? gcpd
: Ret
);
650 static ULONG_PTR FASTCALL
651 IntGetClassLongA(PWND Wnd
, PCLS Class
, int nIndex
)
657 if (nIndex
+ sizeof(ULONG_PTR
) < nIndex
||
658 nIndex
+ sizeof(ULONG_PTR
) > Class
->cbclsExtra
)
660 SetLastError(ERROR_INVALID_PARAMETER
);
663 Ret
= *(PULONG_PTR
)((ULONG_PTR
)(Class
+ 1) + nIndex
);
670 Ret
= (ULONG_PTR
)Class
->cbwndExtra
;
674 Ret
= (ULONG_PTR
)Class
->cbclsExtra
;
677 case GCL_HBRBACKGROUND
:
678 Ret
= (ULONG_PTR
)Class
->hbrBackground
;
679 if (Ret
!= 0 && Ret
< 0x4000)
680 Ret
= (ULONG_PTR
)GetSysColorBrush((ULONG
)Ret
- 1);
684 //ERR("Cls 0x%x GCL_HMODULE 0x%x\n", Wnd->pcls, Class->hModule);
685 Ret
= (ULONG_PTR
)Class
->hModule
;
689 Ret
= (ULONG_PTR
)Class
->lpszClientAnsiMenuName
;
693 Ret
= (ULONG_PTR
)Class
->style
;
697 Ret
= (ULONG_PTR
)Class
->atomNVClassName
;
701 Ret
= Class
->spcur
? (ULONG_PTR
)((PPROCMARKHEAD
)SharedPtrToUser(Class
->spcur
))->h
: 0;
705 Ret
= Class
->spicn
? (ULONG_PTR
)((PPROCMARKHEAD
)SharedPtrToUser(Class
->spicn
))->h
: 0;
709 Ret
= Class
->spicnSm
? (ULONG_PTR
)((PPROCMARKHEAD
)SharedPtrToUser(Class
->spicnSm
))->h
: 0;
713 Ret
= IntGetClsWndProc(Wnd
, Class
, TRUE
);
717 SetLastError(ERROR_INVALID_INDEX
);
725 static ULONG_PTR FASTCALL
726 IntGetClassLongW (PWND Wnd
, PCLS Class
, int nIndex
)
732 if (nIndex
+ sizeof(ULONG_PTR
) < nIndex
||
733 nIndex
+ sizeof(ULONG_PTR
) > Class
->cbclsExtra
)
735 SetLastError(ERROR_INVALID_PARAMETER
);
738 Ret
= *(PULONG_PTR
)((ULONG_PTR
)(Class
+ 1) + nIndex
);
745 Ret
= (ULONG_PTR
)Class
->cbwndExtra
;
749 Ret
= (ULONG_PTR
)Class
->cbclsExtra
;
752 case GCLP_HBRBACKGROUND
:
753 Ret
= (ULONG_PTR
)Class
->hbrBackground
;
754 if (Ret
!= 0 && Ret
< 0x4000)
755 Ret
= (ULONG_PTR
)GetSysColorBrush((ULONG
)Ret
- 1);
759 Ret
= (ULONG_PTR
)Class
->hModule
;
763 Ret
= (ULONG_PTR
)Class
->lpszClientUnicodeMenuName
;
767 Ret
= (ULONG_PTR
)Class
->style
;
771 Ret
= (ULONG_PTR
)Class
->atomNVClassName
;
775 Ret
= Class
->spcur
? (ULONG_PTR
)((PPROCMARKHEAD
)SharedPtrToUser(Class
->spcur
))->h
: 0;
779 Ret
= Class
->spicn
? (ULONG_PTR
)((PPROCMARKHEAD
)SharedPtrToUser(Class
->spicn
))->h
: 0;
783 Ret
= Class
->spicnSm
? (ULONG_PTR
)((PPROCMARKHEAD
)SharedPtrToUser(Class
->spicnSm
))->h
: 0;
787 Ret
= IntGetClsWndProc(Wnd
, Class
, FALSE
);
791 SetLastError(ERROR_INVALID_INDEX
);
803 GetClassLongA(HWND hWnd
, int nIndex
)
809 TRACE("%p %d\n", hWnd
, nIndex
);
811 Wnd
= ValidateHwnd(hWnd
);
817 Class
= DesktopPtrToUser(Wnd
->pcls
);
823 case GCLP_HBRBACKGROUND
:
830 SetLastError(ERROR_INVALID_INDEX
);
834 Ret
= IntGetClassLongA(Wnd
, Class
, nIndex
);
838 Ret
= IntGetClassLongA(Wnd
, Class
, nIndex
);
843 WARN("Invalid class for hwnd 0x%p!\n", hWnd
);
846 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
859 GetClassLongW ( HWND hWnd
, int nIndex
)
865 TRACE("%p %d\n", hWnd
, nIndex
);
867 Wnd
= ValidateHwnd(hWnd
);
873 Class
= DesktopPtrToUser(Wnd
->pcls
);
879 case GCLP_HBRBACKGROUND
:
886 SetLastError(ERROR_INVALID_INDEX
);
890 Ret
= IntGetClassLongW(Wnd
, Class
, nIndex
);
894 Ret
= IntGetClassLongW(Wnd
, Class
, nIndex
);
899 WARN("Invalid class for hwnd 0x%p!\n", hWnd
);
902 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
917 GetClassLongPtrA(HWND hWnd
,
924 TRACE("%p %d\n", hWnd
, nIndex
);
926 Wnd
= ValidateHwnd(hWnd
);
932 Class
= DesktopPtrToUser(Wnd
->pcls
);
935 Ret
= IntGetClassLongA(Wnd
, Class
, nIndex
);
939 WARN("Invalid class for hwnd 0x%p!\n", hWnd
);
942 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
956 GetClassLongPtrW(HWND hWnd
,
963 TRACE("%p %d\n", hWnd
, nIndex
);
965 Wnd
= ValidateHwnd(hWnd
);
971 Class
= DesktopPtrToUser(Wnd
->pcls
);
974 Ret
= IntGetClassLongW(Wnd
, Class
, nIndex
);
978 WARN("Invalid class for hwnd 0x%p!\n", hWnd
);
981 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1001 WCHAR tmpbuf
[MAX_ATOM_LEN
+ 1];
1004 if (nMaxCount
<= 0) return 0;
1005 if (!GetClassNameW( hWnd
, tmpbuf
, sizeof(tmpbuf
)/sizeof(WCHAR
) )) return 0;
1006 RtlUnicodeToMultiByteN( lpClassName
, nMaxCount
- 1, (PULONG
)&len
, tmpbuf
, strlenW(tmpbuf
) * sizeof(WCHAR
) );
1007 lpClassName
[len
] = 0;
1009 TRACE("%p class/atom: %s/%04x %x\n", hWnd
,
1010 IS_ATOM(lpClassName
) ? NULL
: lpClassName
,
1011 IS_ATOM(lpClassName
) ? lpClassName
: 0,
1028 UNICODE_STRING ClassName
;
1031 RtlInitEmptyUnicodeString(&ClassName
,
1033 nMaxCount
* sizeof(WCHAR
));
1035 Result
= NtUserGetClassName(hWnd
,
1039 TRACE("%p class/atom: %S/%04x %x\n", hWnd
,
1040 IS_ATOM(lpClassName
) ? NULL
: lpClassName
,
1041 IS_ATOM(lpClassName
) ? lpClassName
: 0,
1061 if (offset
< 0) return GetClassLongA( hwnd
, offset
);
1063 Wnd
= ValidateHwnd(hwnd
);
1067 class = DesktopPtrToUser(Wnd
->pcls
);
1068 if (class == NULL
) return 0;
1070 if (offset
<= class->cbclsExtra
- sizeof(WORD
))
1071 memcpy( &retvalue
, (char *)(class + 1) + offset
, sizeof(retvalue
) );
1073 SetLastError( ERROR_INVALID_INDEX
);
1079 LONG_PTR
IntGetWindowLong( HWND hwnd
, INT offset
, UINT size
, BOOL unicode
)
1081 LONG_PTR retvalue
= 0;
1084 if (offset
== GWLP_HWNDPARENT
)
1086 HWND parent
= GetAncestor( hwnd
, GA_PARENT
);
1087 if (parent
== GetDesktopWindow()) parent
= GetWindow( hwnd
, GW_OWNER
);
1088 return (ULONG_PTR
)parent
;
1091 if (!(wndPtr
= ValidateHwnd( hwnd
)))
1093 SetLastError( ERROR_INVALID_WINDOW_HANDLE
);
1097 if (offset
>= 0 && wndPtr
->fnid
!= FNID_DESKTOP
)
1099 if (offset
> (int)(wndPtr
->cbwndExtra
- size
))
1101 WARN("Invalid offset %d\n", offset
);
1102 SetLastError( ERROR_INVALID_INDEX
);
1105 retvalue
= *((LONG_PTR
*)((PCHAR
)(wndPtr
+ 1) + offset
));
1107 /* WINE: special case for dialog window procedure */
1108 //if ((offset == DWLP_DLGPROC) && (size == sizeof(LONG_PTR)) && (wndPtr->flags & WIN_ISDIALOG))
1109 // retvalue = (LONG_PTR)IntGetWndProc( (WNDPROC)retvalue, unicode );
1115 case GWLP_USERDATA
: retvalue
= wndPtr
->dwUserData
; break;
1116 case GWL_STYLE
: retvalue
= wndPtr
->style
; break;
1117 case GWL_EXSTYLE
: retvalue
= wndPtr
->ExStyle
; break;
1118 case GWLP_ID
: retvalue
= wndPtr
->IDMenu
; break;
1119 case GWLP_HINSTANCE
: retvalue
= (ULONG_PTR
)wndPtr
->hModule
; break;
1122 if (!TestWindowProcess(wndPtr
))
1124 SetLastError(ERROR_ACCESS_DENIED
);
1127 retvalue
= (ULONG_PTR
)IntGetWndProc(wndPtr
, !unicode
);
1131 WARN("Unknown offset %d\n", offset
);
1132 SetLastError( ERROR_INVALID_INDEX
);
1143 GetWindowLongA ( HWND hWnd
, int nIndex
)
1145 return IntGetWindowLong( hWnd
, nIndex
, sizeof(LONG
), FALSE
);
1153 GetWindowLongW(HWND hWnd
, int nIndex
)
1155 return IntGetWindowLong( hWnd
, nIndex
, sizeof(LONG
), TRUE
);
1164 GetWindowLongPtrA(HWND hWnd
,
1167 return IntGetWindowLong( hWnd
, nIndex
, sizeof(LONG_PTR
), FALSE
);
1175 GetWindowLongPtrW(HWND hWnd
,
1178 return IntGetWindowLong( hWnd
, nIndex
, sizeof(LONG_PTR
), TRUE
);
1188 GetWindowWord(HWND hWnd
, int nIndex
)
1193 case GWLP_HINSTANCE
:
1194 case GWLP_HWNDPARENT
:
1199 WARN("Invalid offset %d\n", nIndex
);
1200 SetLastError( ERROR_INVALID_INDEX
);
1205 return IntGetWindowLong( hWnd
, nIndex
, sizeof(WORD
), FALSE
);
1213 RealGetWindowClassW(
1218 UNICODE_STRING ClassName
;
1220 RtlInitEmptyUnicodeString(&ClassName
,
1222 cchType
* sizeof(WCHAR
));
1224 return NtUserGetClassName(hwnd
,TRUE
,&ClassName
);
1233 RealGetWindowClassA(
1238 WCHAR tmpbuf
[MAX_ATOM_LEN
+ 1];
1241 if ((INT
)cchType
<= 0) return 0;
1242 if (!RealGetWindowClassW( hwnd
, tmpbuf
, sizeof(tmpbuf
)/sizeof(WCHAR
) )) return 0;
1243 RtlUnicodeToMultiByteN( pszType
, cchType
- 1, (PULONG
)&len
, tmpbuf
, strlenW(tmpbuf
) * sizeof(WCHAR
) );
1249 * Create a small icon based on a standard icon
1251 #if 0 // Keep vintage code from revision 18764 by GvG!
1253 CreateSmallIcon(HICON StdIcon
)
1255 HICON SmallIcon
= NULL
;
1258 int SmallIconHeight
;
1259 BITMAP StdBitmapInfo
;
1260 HDC hSourceDc
= NULL
;
1263 HBITMAP OldSourceBitmap
= NULL
;
1264 HBITMAP OldDestBitmap
= NULL
;
1266 SmallInfo
.hbmColor
= NULL
;
1267 SmallInfo
.hbmMask
= NULL
;
1269 /* We need something to work with... */
1270 if (NULL
== StdIcon
)
1275 SmallIconWidth
= GetSystemMetrics(SM_CXSMICON
);
1276 SmallIconHeight
= GetSystemMetrics(SM_CYSMICON
);
1277 if (! GetIconInfo(StdIcon
, &StdInfo
))
1279 ERR("Failed to get icon info for icon 0x%x\n", StdIcon
);
1282 if (! GetObjectW(StdInfo
.hbmMask
, sizeof(BITMAP
), &StdBitmapInfo
))
1284 ERR("Failed to get bitmap info for icon 0x%x bitmap 0x%x\n",
1285 StdIcon
, StdInfo
.hbmColor
);
1288 if (StdBitmapInfo
.bmWidth
== SmallIconWidth
&&
1289 StdBitmapInfo
.bmHeight
== SmallIconHeight
)
1291 /* Icon already has the correct dimensions */
1295 hSourceDc
= CreateCompatibleDC(NULL
);
1296 if (NULL
== hSourceDc
)
1298 ERR("Failed to create source DC\n");
1301 hDestDc
= CreateCompatibleDC(NULL
);
1302 if (NULL
== hDestDc
)
1304 ERR("Failed to create dest DC\n");
1308 OldSourceBitmap
= SelectObject(hSourceDc
, StdInfo
.hbmColor
);
1309 if (NULL
== OldSourceBitmap
)
1311 ERR("Failed to select source color bitmap\n");
1314 SmallInfo
.hbmColor
= CreateCompatibleBitmap(hSourceDc
, SmallIconWidth
,
1316 if (NULL
== SmallInfo
.hbmColor
)
1318 ERR("Failed to create color bitmap\n");
1321 OldDestBitmap
= SelectObject(hDestDc
, SmallInfo
.hbmColor
);
1322 if (NULL
== OldDestBitmap
)
1324 ERR("Failed to select dest color bitmap\n");
1327 if (! StretchBlt(hDestDc
, 0, 0, SmallIconWidth
, SmallIconHeight
,
1328 hSourceDc
, 0, 0, StdBitmapInfo
.bmWidth
,
1329 StdBitmapInfo
.bmHeight
, SRCCOPY
))
1331 ERR("Failed to stretch color bitmap\n");
1335 if (NULL
== SelectObject(hSourceDc
, StdInfo
.hbmMask
))
1337 ERR("Failed to select source mask bitmap\n");
1340 SmallInfo
.hbmMask
= CreateCompatibleBitmap(hSourceDc
, SmallIconWidth
, SmallIconHeight
);
1341 if (NULL
== SmallInfo
.hbmMask
)
1343 ERR("Failed to create mask bitmap\n");
1346 if (NULL
== SelectObject(hDestDc
, SmallInfo
.hbmMask
))
1348 ERR("Failed to select dest mask bitmap\n");
1351 if (! StretchBlt(hDestDc
, 0, 0, SmallIconWidth
, SmallIconHeight
,
1352 hSourceDc
, 0, 0, StdBitmapInfo
.bmWidth
,
1353 StdBitmapInfo
.bmHeight
, SRCCOPY
))
1355 ERR("Failed to stretch mask bitmap\n");
1359 SmallInfo
.fIcon
= TRUE
;
1360 SmallInfo
.xHotspot
= SmallIconWidth
/ 2;
1361 SmallInfo
.yHotspot
= SmallIconHeight
/ 2;
1362 SmallIcon
= CreateIconIndirect(&SmallInfo
);
1363 if (NULL
== SmallIcon
)
1365 ERR("Failed to create icon\n");
1370 if (NULL
!= SmallInfo
.hbmMask
)
1372 DeleteObject(SmallInfo
.hbmMask
);
1374 if (NULL
!= OldDestBitmap
)
1376 SelectObject(hDestDc
, OldDestBitmap
);
1378 if (NULL
!= SmallInfo
.hbmColor
)
1380 DeleteObject(SmallInfo
.hbmColor
);
1382 if (NULL
!= hDestDc
)
1386 if (NULL
!= OldSourceBitmap
)
1388 SelectObject(hSourceDc
, OldSourceBitmap
);
1390 if (NULL
!= hSourceDc
)
1392 DeleteDC(hSourceDc
);
1400 RegisterClassExWOWW(WNDCLASSEXW
*lpwcx
,
1407 WNDCLASSEXW WndClass
;
1408 UNICODE_STRING ClassName
;
1409 UNICODE_STRING ClassVersion
;
1410 UNICODE_STRING MenuName
= {0};
1411 CLSMENUNAME clsMenuName
;
1412 ANSI_STRING AnsiMenuName
;
1413 LPCWSTR lpszClsVersion
;
1415 if (lpwcx
== NULL
|| lpwcx
->cbSize
!= sizeof(WNDCLASSEXW
) ||
1416 lpwcx
->cbClsExtra
< 0 || lpwcx
->cbWndExtra
< 0 ||
1417 lpwcx
->lpszClassName
== NULL
)
1419 TRACE("RegisterClassExWOWW Invalid Parameter Error!\n");
1420 SetLastError(ERROR_INVALID_PARAMETER
);
1426 if (!RegisterDefaultClasses
) RegisterSystemControls();
1429 * On real Windows this looks more like:
1430 * if (lpwcx->hInstance == User32Instance &&
1431 * *(PULONG)((ULONG_PTR)NtCurrentTeb() + 0x6D4) & 0x400)
1432 * But since I have no idea what the magic field in the
1433 * TEB structure means, I rather decided to omit that.
1436 GetWin32ClientInfo()->dwExpWinVer & (WINVER == 0x400)
1438 if (lpwcx
->hInstance
== User32Instance
)
1440 TRACE("RegisterClassExWOWW User32Instance!\n");
1441 SetLastError(ERROR_INVALID_PARAMETER
);
1444 /* Yes, this is correct. We should modify the passed structure. */
1445 if (lpwcx
->hInstance
== NULL
)
1446 ((WNDCLASSEXW
*)lpwcx
)->hInstance
= GetModuleHandleW(NULL
);
1448 RtlCopyMemory(&WndClass
, lpwcx
, sizeof(WNDCLASSEXW
));
1450 if (NULL == WndClass.hIconSm)
1452 WndClass.hIconSm = CreateSmallIcon(WndClass.hIcon);
1455 RtlInitEmptyAnsiString(&AnsiMenuName
, NULL
, 0);
1456 if (WndClass
.lpszMenuName
!= NULL
)
1458 if (!IS_INTRESOURCE(WndClass
.lpszMenuName
))
1460 if (WndClass
.lpszMenuName
[0])
1462 RtlInitUnicodeString(&MenuName
, WndClass
.lpszMenuName
);
1463 RtlUnicodeStringToAnsiString( &AnsiMenuName
, &MenuName
, TRUE
);
1468 MenuName
.Buffer
= (LPWSTR
)WndClass
.lpszMenuName
;
1469 AnsiMenuName
.Buffer
= (PCHAR
)WndClass
.lpszMenuName
;
1473 if (IS_ATOM(WndClass
.lpszClassName
))
1476 ClassName
.MaximumLength
= 0;
1477 ClassName
.Buffer
= (LPWSTR
)WndClass
.lpszClassName
;
1481 RtlInitUnicodeString(&ClassName
, WndClass
.lpszClassName
);
1484 ClassVersion
= ClassName
;
1487 lpszClsVersion
= ClassNameToVersion(lpwcx
->lpszClassName
, NULL
, NULL
, NULL
, FALSE
);
1490 RtlInitUnicodeString(&ClassVersion
, lpszClsVersion
);
1494 clsMenuName
.pszClientAnsiMenuName
= AnsiMenuName
.Buffer
;
1495 clsMenuName
.pwszClientUnicodeMenuName
= MenuName
.Buffer
;
1496 clsMenuName
.pusMenuName
= &MenuName
;
1498 Atom
= NtUserRegisterClassExWOW( &WndClass
,
1506 TRACE("atom=%04x wndproc=%p hinst=%p bg=%p style=%08x clsExt=%d winExt=%d class=%p\n",
1507 Atom
, lpwcx
->lpfnWndProc
, lpwcx
->hInstance
, lpwcx
->hbrBackground
,
1508 lpwcx
->style
, lpwcx
->cbClsExtra
, lpwcx
->cbWndExtra
, WndClass
);
1517 RegisterClassExA(CONST WNDCLASSEXA
*lpwcx
)
1520 WNDCLASSEXW WndClass
;
1521 WCHAR mname
[MAX_BUFFER_LEN
];
1522 WCHAR cname
[MAX_BUFFER_LEN
];
1524 RtlCopyMemory(&WndClass
, lpwcx
, sizeof(WNDCLASSEXA
));
1526 if (WndClass
.lpszMenuName
!= NULL
)
1528 if (!IS_INTRESOURCE(WndClass
.lpszMenuName
))
1530 if (WndClass
.lpszMenuName
[0])
1532 if (!MultiByteToWideChar( CP_ACP
, 0, lpwcx
->lpszMenuName
, -1, mname
, MAX_ATOM_LEN
+ 1 )) return 0;
1534 WndClass
.lpszMenuName
= mname
;
1539 if (!IS_ATOM(WndClass
.lpszClassName
))
1541 if (!MultiByteToWideChar( CP_ACP
, 0, lpwcx
->lpszClassName
, -1, cname
, MAX_ATOM_LEN
+ 1 )) return 0;
1543 WndClass
.lpszClassName
= cname
;
1546 Atom
= RegisterClassExWOWW( &WndClass
,
1552 TRACE("A atom=%04x wndproc=%p hinst=%p bg=%p style=%08x clsExt=%d winExt=%d class=%p\n",
1553 Atom
, lpwcx
->lpfnWndProc
, lpwcx
->hInstance
, lpwcx
->hbrBackground
,
1554 lpwcx
->style
, lpwcx
->cbClsExtra
, lpwcx
->cbWndExtra
, WndClass
);
1563 RegisterClassExW(CONST WNDCLASSEXW
*lpwcx
)
1567 Atom
= RegisterClassExWOWW( (WNDCLASSEXW
*)lpwcx
, 0, 0, 0, TRUE
);
1569 TRACE("W atom=%04x wndproc=%p hinst=%p bg=%p style=%08x clsExt=%d winExt=%d\n",
1570 Atom
, lpwcx
->lpfnWndProc
, lpwcx
->hInstance
, lpwcx
->hbrBackground
,
1571 lpwcx
->style
, lpwcx
->cbClsExtra
, lpwcx
->cbWndExtra
);
1580 RegisterClassA(CONST WNDCLASSA
*lpWndClass
)
1584 if (lpWndClass
== NULL
)
1587 RtlCopyMemory(&Class
.style
, lpWndClass
, sizeof(WNDCLASSA
));
1588 Class
.cbSize
= sizeof(WNDCLASSEXA
);
1589 Class
.hIconSm
= NULL
;
1591 return RegisterClassExA(&Class
);
1598 RegisterClassW(CONST WNDCLASSW
*lpWndClass
)
1602 if (lpWndClass
== NULL
)
1605 RtlCopyMemory(&Class
.style
, lpWndClass
, sizeof(WNDCLASSW
));
1606 Class
.cbSize
= sizeof(WNDCLASSEXW
);
1607 Class
.hIconSm
= NULL
;
1609 return RegisterClassExW(&Class
);
1617 SetClassLongA (HWND hWnd
,
1621 PSTR lpStr
= (PSTR
)(ULONG_PTR
)dwNewLong
;
1622 UNICODE_STRING Value
= {0};
1623 BOOL Allocated
= FALSE
;
1626 /* FIXME - portability!!!! */
1628 if (nIndex
== GCL_MENUNAME
&& lpStr
!= NULL
)
1630 if (!IS_INTRESOURCE(lpStr
))
1632 if (!RtlCreateUnicodeStringFromAsciiz(&Value
,
1635 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1642 Value
.Buffer
= (PWSTR
)lpStr
;
1644 dwNewLong
= (LONG_PTR
)&Value
;
1646 else if (nIndex
== GCW_ATOM
&& lpStr
!= NULL
)
1648 if (!IS_ATOM(lpStr
))
1650 if (!RtlCreateUnicodeStringFromAsciiz(&Value
,
1653 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1660 Value
.Buffer
= (PWSTR
)lpStr
;
1662 dwNewLong
= (LONG_PTR
)&Value
;
1665 Ret
= (DWORD
)NtUserSetClassLong(hWnd
,
1672 RtlFreeUnicodeString(&Value
);
1684 SetClassLongW(HWND hWnd
,
1688 PWSTR lpStr
= (PWSTR
)(ULONG_PTR
)dwNewLong
;
1689 UNICODE_STRING Value
= {0};
1691 TRACE("%p %d %lx\n", hWnd
, nIndex
, dwNewLong
);
1693 /* FIXME - portability!!!! */
1695 if (nIndex
== GCL_MENUNAME
&& lpStr
!= NULL
)
1697 if (!IS_INTRESOURCE(lpStr
))
1699 RtlInitUnicodeString(&Value
,
1703 Value
.Buffer
= lpStr
;
1705 dwNewLong
= (LONG_PTR
)&Value
;
1707 else if (nIndex
== GCW_ATOM
&& lpStr
!= NULL
)
1709 if (!IS_ATOM(lpStr
))
1711 RtlInitUnicodeString(&Value
,
1715 Value
.Buffer
= lpStr
;
1717 dwNewLong
= (LONG_PTR
)&Value
;
1720 return (DWORD
)NtUserSetClassLong(hWnd
,
1732 SetClassLongPtrA(HWND hWnd
,
1745 SetClassLongPtrW(HWND hWnd
,
1764 * NOTE: Obsoleted in 32-bit windows
1767 if ((nIndex
< 0) && (nIndex
!= GCW_ATOM
))
1770 return (WORD
) SetClassLongW ( hWnd
, nIndex
, wNewWord
);
1778 SetWindowWord ( HWND hWnd
,int nIndex
,WORD wNewWord
)
1783 case GWLP_HINSTANCE
:
1784 case GWLP_HWNDPARENT
:
1789 WARN("Invalid offset %d\n", nIndex
);
1790 SetLastError( ERROR_INVALID_INDEX
);
1795 return NtUserSetWindowLong( hWnd
, nIndex
, wNewWord
, FALSE
);
1809 return NtUserSetWindowLong(hWnd
, nIndex
, dwNewLong
, TRUE
);
1822 return NtUserSetWindowLong(hWnd
, nIndex
, dwNewLong
, FALSE
);
1831 SetWindowLongPtrA(HWND hWnd
,
1835 return NtUserSetWindowLong(hWnd
, nIndex
, dwNewLong
, FALSE
);
1843 SetWindowLongPtrW(HWND hWnd
,
1847 return NtUserSetWindowLong(hWnd
, nIndex
, dwNewLong
, FALSE
);
1858 HINSTANCE hInstance
)
1860 UNICODE_STRING ClassName
= {0};
1862 LPCWSTR lpszClsVersion
;
1863 BOOL ConvertedString
= FALSE
;
1865 TRACE("class/atom: %s/%04x %p\n",
1866 IS_ATOM(lpClassName
) ? NULL
: lpClassName
,
1867 IS_ATOM(lpClassName
) ? lpClassName
: 0,
1870 lpszClsVersion
= ClassNameToVersion(lpClassName
, NULL
, NULL
, NULL
, TRUE
);
1873 RtlInitUnicodeString(&ClassName
, lpszClsVersion
);
1875 else if (!IS_ATOM(lpClassName
))
1877 ConvertedString
= TRUE
;
1878 if (!RtlCreateUnicodeStringFromAsciiz(&ClassName
, lpClassName
))
1880 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1886 ClassName
.Buffer
= (PWSTR
)((ULONG_PTR
)lpClassName
);
1889 Ret
= NtUserUnregisterClass(&ClassName
, hInstance
, 0);
1891 if (ConvertedString
)
1892 RtlFreeUnicodeString(&ClassName
);
1904 LPCWSTR lpClassName
,
1905 HINSTANCE hInstance
)
1907 UNICODE_STRING ClassName
= {0};
1908 LPCWSTR lpszClsVersion
;
1910 TRACE("class/atom: %S/%04x %p\n",
1911 IS_ATOM(lpClassName
) ? NULL
: lpClassName
,
1912 IS_ATOM(lpClassName
) ? lpClassName
: 0,
1915 lpszClsVersion
= ClassNameToVersion(lpClassName
, NULL
, NULL
, NULL
, FALSE
);
1918 RtlInitUnicodeString(&ClassName
, lpszClsVersion
);
1920 else if (!IS_ATOM(lpClassName
))
1922 RtlInitUnicodeString(&ClassName
, lpClassName
);
1926 ClassName
.Buffer
= (PWSTR
)((ULONG_PTR
)lpClassName
);
1929 return NtUserUnregisterClass(&ClassName
, hInstance
, 0);