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 WINE_DEFAULT_DEBUG_CHANNEL(user32
);
15 #define USE_VERSIONED_CLASSES
17 /* From rtl/actctx.c and must match! */
18 struct strsection_header
30 struct wndclass_redirect_data
35 ULONG name_offset
; /* versioned name offset */
37 ULONG module_offset
;/* container name offset */
41 // Use wine hack to process extended context classes.
43 /***********************************************************************
46 LPCWSTR
is_comctl32_class( const WCHAR
*name
)
48 static const WCHAR classesW
[][20] =
50 {'C','o','m','b','o','B','o','x','E','x','3','2',0},
51 {'m','s','c','t','l','s','_','h','o','t','k','e','y','3','2',0},
52 {'m','s','c','t','l','s','_','p','r','o','g','r','e','s','s','3','2',0},
53 {'m','s','c','t','l','s','_','s','t','a','t','u','s','b','a','r','3','2',0},
54 {'m','s','c','t','l','s','_','t','r','a','c','k','b','a','r','3','2',0},
55 {'m','s','c','t','l','s','_','u','p','d','o','w','n','3','2',0},
56 {'N','a','t','i','v','e','F','o','n','t','C','t','l',0},
57 {'R','e','B','a','r','W','i','n','d','o','w','3','2',0},
58 {'S','y','s','A','n','i','m','a','t','e','3','2',0},
59 {'S','y','s','D','a','t','e','T','i','m','e','P','i','c','k','3','2',0},
60 {'S','y','s','H','e','a','d','e','r','3','2',0},
61 {'S','y','s','I','P','A','d','d','r','e','s','s','3','2',0},
62 {'S','y','s','L','i','s','t','V','i','e','w','3','2',0},
63 {'S','y','s','M','o','n','t','h','C','a','l','3','2',0},
64 {'S','y','s','P','a','g','e','r',0},
65 {'S','y','s','T','a','b','C','o','n','t','r','o','l','3','2',0},
66 {'S','y','s','T','r','e','e','V','i','e','w','3','2',0},
67 {'T','o','o','l','b','a','r','W','i','n','d','o','w','3','2',0},
68 {'t','o','o','l','t','i','p','s','_','c','l','a','s','s','3','2',0},
71 int min
= 0, max
= (sizeof(classesW
) / sizeof(classesW
[0])) - 1;
75 int res
, pos
= (min
+ max
) / 2;
76 if (!(res
= strcmpiW( name
, classesW
[pos
] ))) return classesW
[pos
];
77 if (res
< 0) max
= pos
- 1;
86 const void* lpszClass
,
88 LPCWSTR
*plpLibFileName
,
92 LPCWSTR VersionedClass
= NULL
;
93 #ifdef USE_VERSIONED_CLASSES
96 UNICODE_STRING SectionName
;
97 WCHAR SectionNameBuf
[MAX_PATH
] = {0};
98 ACTCTX_SECTION_KEYED_DATA KeyedData
= { sizeof(KeyedData
) };
102 ERR("Null class given !\n");
106 if (IS_ATOM(lpszClass
))
108 RtlInitEmptyUnicodeString(&SectionName
, SectionNameBuf
, sizeof(SectionNameBuf
));
109 if(!NtUserGetAtomName(LOWORD((DWORD_PTR
)lpszClass
), &SectionName
))
111 ERR("Couldn't get atom name for atom %x !\n", LOWORD((DWORD_PTR
)lpszClass
));
114 SectionName
.Length
= (USHORT
)wcslen(SectionNameBuf
) * sizeof(WCHAR
);
115 TRACE("ClassNameToVersion got name %wZ from atom\n", &SectionName
);
121 ANSI_STRING AnsiString
;
122 RtlInitAnsiString(&AnsiString
, lpszClass
);
123 RtlInitEmptyUnicodeString(&SectionName
, SectionNameBuf
, sizeof(SectionNameBuf
));
124 RtlAnsiStringToUnicodeString(&SectionName
, &AnsiString
, FALSE
);
128 RtlInitUnicodeString(&SectionName
, lpszClass
);
131 #ifdef USE_VERSIONED_CLASSES
132 Status
= RtlFindActivationContextSectionString( FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX
,
134 ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION
,
138 if (NT_SUCCESS(Status
) && KeyedData
.ulDataFormatVersion
== 1)
140 struct strsection_header
*SectionHeader
= KeyedData
.lpSectionBase
;
142 /* Find activation context */
143 if(SectionHeader
&& SectionHeader
->count
> 0)
145 struct wndclass_redirect_data
*WindowRedirectionData
= KeyedData
.lpData
;
146 if(WindowRedirectionData
&& WindowRedirectionData
->module_len
)
148 LPCWSTR lpLibFileName
;
150 VersionedClass
= (WCHAR
*)((BYTE
*)WindowRedirectionData
+ WindowRedirectionData
->name_offset
);
151 lpLibFileName
= (WCHAR
*)((BYTE
*)KeyedData
.lpSectionBase
+ WindowRedirectionData
->module_offset
);
152 TRACE("Returning VersionedClass=%S, plpLibFileName=%S for class %S\n", VersionedClass
, lpLibFileName
, SectionName
.Buffer
);
154 if (pContext
) *pContext
= KeyedData
.hActCtx
;
155 if (plpLibFileName
) *plpLibFileName
= lpLibFileName
;
161 if (KeyedData
.hActCtx
)
162 RtlReleaseActivationContext(KeyedData
.hActCtx
);
165 #ifndef DEFAULT_ACTIVATION_CONTEXTS_SUPPORTED
166 /* This block is a hack! */
170 * In windows the default activation context always contains comctl32v5
171 * In reactos we don't have a default activation context so we
174 VersionedClass
= is_comctl32_class(SectionName
.Buffer
);
177 if (pContext
) *pContext
= 0;
178 if (plpLibFileName
) *plpLibFileName
= L
"comctl32";
184 * The returned strings are pointers in the activation context and
185 * will get freed when the activation context gets freed
187 return VersionedClass
;
191 // Ref: http://yvs-it.blogspot.com/2010/04/initcommoncontrolsex.html
195 VersionRegisterClass(
197 LPCWSTR lpLibFileName
,
199 HMODULE
* phLibModule
)
202 HMODULE hLibModule
= NULL
;
203 PREGISTERCLASSNAMEW pRegisterClassNameW
;
204 UNICODE_STRING ClassName
;
205 WCHAR ClassNameBuf
[MAX_PATH
] = {0};
206 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED Frame
= { sizeof(Frame
), 1 };
208 ERR("VersionRegisterClass: Attempting to call RegisterClassNameW in %S.\n", lpLibFileName
);
210 RtlActivateActivationContextUnsafeFast(&Frame
, Contex
);
214 hLibModule
= LoadLibraryW(lpLibFileName
);
217 if ((pRegisterClassNameW
= (void*)GetProcAddress(hLibModule
, "RegisterClassNameW")))
219 if (IS_ATOM(pszClass
))
221 RtlInitEmptyUnicodeString(&ClassName
, ClassNameBuf
, sizeof(ClassNameBuf
));
222 if (!NtUserGetAtomName(LOWORD((DWORD_PTR
)pszClass
), &ClassName
))
224 ERR("Error while verifying ATOM\n");
225 _SEH2_YIELD(goto Error_Exit
);
227 pszClass
= ClassName
.Buffer
;
229 Ret
= pRegisterClassNameW(pszClass
);
233 WARN("No RegisterClassNameW PROC\n");
237 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
239 ERR("Got exception while trying to call RegisterClassNameW!\n");
244 if (Ret
|| !hLibModule
)
246 if (phLibModule
) *phLibModule
= hLibModule
;
250 DWORD dwLastError
= GetLastError();
251 FreeLibrary(hLibModule
);
252 SetLastError(dwLastError
);
255 RtlDeactivateActivationContextUnsafeFast(&Frame
);
269 UNICODE_STRING ClassName
= {0};
271 HMODULE hLibModule
= NULL
;
273 BOOL Ret
, ClassFound
= FALSE
, ConvertedString
= FALSE
;
274 LPCWSTR lpszClsVersion
;
276 LPCWSTR lpLibFileName
= NULL
;
278 TRACE("%p class/atom: %s/%04x %p\n", hInstance
,
279 IS_ATOM(lpszClass
) ? NULL
: lpszClass
,
280 IS_ATOM(lpszClass
) ? lpszClass
: 0,
285 SetLastError(ERROR_NOACCESS
);
289 if (hInstance
== User32Instance
)
294 if (lpszClass
== NULL
)
296 SetLastError(ERROR_INVALID_PARAMETER
);
300 lpszClsVersion
= ClassNameToVersion(lpszClass
, NULL
, &lpLibFileName
, &pCtx
, TRUE
);
303 RtlInitUnicodeString(&ClassName
, lpszClsVersion
);
305 else if (IS_ATOM(lpszClass
))
307 ClassName
.Buffer
= (PWSTR
)((ULONG_PTR
)lpszClass
);
311 ConvertedString
= TRUE
;
312 if (!RtlCreateUnicodeStringFromAsciiz(&ClassName
, lpszClass
))
314 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
319 if (!RegisterDefaultClasses
)
321 TRACE("RegisterSystemControls\n");
322 RegisterSystemControls();
327 Ret
= NtUserGetClassInfo(hInstance
,
329 (LPWNDCLASSEXW
)lpwcx
,
330 (LPWSTR
*)&pszMenuName
,
333 if (!lpLibFileName
) break;
336 dwLastError
= GetLastError();
337 if ( dwLastError
== ERROR_CANNOT_FIND_WND_CLASS
||
338 dwLastError
== ERROR_CLASS_DOES_NOT_EXIST
)
340 ClassFound
= VersionRegisterClass(ClassName
.Buffer
, lpLibFileName
, pCtx
, &hLibModule
);
341 if (ClassFound
) continue;
346 dwLastError
= GetLastError();
347 FreeLibrary(hLibModule
);
348 SetLastError(dwLastError
);
356 lpwcx
->lpszClassName
= lpszClass
;
357 // lpwcx->lpszMenuName = pszMenuName;
362 RtlFreeUnicodeString(&ClassName
);
379 UNICODE_STRING ClassName
= {0};
381 HMODULE hLibModule
= NULL
;
383 BOOL Ret
, ClassFound
= FALSE
;
384 LPCWSTR lpszClsVersion
;
386 LPCWSTR lpLibFileName
= NULL
;
388 TRACE("%p class/atom: %S/%04x %p\n", hInstance
,
389 IS_ATOM(lpszClass
) ? NULL
: lpszClass
,
390 IS_ATOM(lpszClass
) ? lpszClass
: 0,
393 /* From wine, for speed only, ReactOS supports the correct return in
394 * Win32k. cbSize is ignored.
398 SetLastError( ERROR_NOACCESS
);
402 if (hInstance
== User32Instance
)
407 if (lpszClass
== NULL
)
409 SetLastError(ERROR_INVALID_PARAMETER
);
413 lpszClsVersion
= ClassNameToVersion(lpszClass
, NULL
, &lpLibFileName
, &pCtx
, FALSE
);
416 RtlInitUnicodeString(&ClassName
, lpszClsVersion
);
418 else if (IS_ATOM(lpszClass
))
420 ClassName
.Buffer
= (PWSTR
)((ULONG_PTR
)lpszClass
);
424 RtlInitUnicodeString(&ClassName
, lpszClass
);
427 if (!RegisterDefaultClasses
)
429 TRACE("RegisterSystemControls\n");
430 RegisterSystemControls();
435 Ret
= NtUserGetClassInfo( hInstance
,
441 if (!lpLibFileName
) break;
444 dwLastError
= GetLastError();
445 if ( dwLastError
== ERROR_CANNOT_FIND_WND_CLASS
||
446 dwLastError
== ERROR_CLASS_DOES_NOT_EXIST
)
448 ClassFound
= VersionRegisterClass(ClassName
.Buffer
, lpLibFileName
, pCtx
, &hLibModule
);
449 if (ClassFound
) continue;
454 dwLastError
= GetLastError();
455 FreeLibrary(hLibModule
);
456 SetLastError(dwLastError
);
464 lpwcx
->lpszClassName
= lpszClass
;
465 // lpwcx->lpszMenuName = pszMenuName;
479 LPWNDCLASSA lpWndClass
)
484 retval
= GetClassInfoExA(hInstance
, lpClassName
, &wcex
);
487 lpWndClass
->style
= wcex
.style
;
488 lpWndClass
->lpfnWndProc
= wcex
.lpfnWndProc
;
489 lpWndClass
->cbClsExtra
= wcex
.cbClsExtra
;
490 lpWndClass
->cbWndExtra
= wcex
.cbWndExtra
;
491 lpWndClass
->hInstance
= wcex
.hInstance
;
492 lpWndClass
->hIcon
= wcex
.hIcon
;
493 lpWndClass
->hCursor
= wcex
.hCursor
;
494 lpWndClass
->hbrBackground
= wcex
.hbrBackground
;
495 lpWndClass
->lpszMenuName
= wcex
.lpszMenuName
;
496 lpWndClass
->lpszClassName
= wcex
.lpszClassName
;
510 LPWNDCLASSW lpWndClass
)
515 retval
= GetClassInfoExW(hInstance
, lpClassName
, &wcex
);
518 lpWndClass
->style
= wcex
.style
;
519 lpWndClass
->lpfnWndProc
= wcex
.lpfnWndProc
;
520 lpWndClass
->cbClsExtra
= wcex
.cbClsExtra
;
521 lpWndClass
->cbWndExtra
= wcex
.cbWndExtra
;
522 lpWndClass
->hInstance
= wcex
.hInstance
;
523 lpWndClass
->hIcon
= wcex
.hIcon
;
524 lpWndClass
->hCursor
= wcex
.hCursor
;
525 lpWndClass
->hbrBackground
= wcex
.hbrBackground
;
526 lpWndClass
->lpszMenuName
= wcex
.lpszMenuName
;
527 lpWndClass
->lpszClassName
= wcex
.lpszClassName
;
533 // Based on find_winproc... Fixes many whine tests......
536 IntGetClsWndProc(PWND pWnd
, PCLS Class
, BOOL Ansi
)
539 ULONG_PTR gcpd
, Ret
= 0;
540 // If server side, sweep through proc list and return the client side proc.
541 if (Class
->CSF_flags
& CSF_SERVERSIDEPROC
)
542 { // Always scan through the list due to wine class "deftest".
543 for ( i
= FNID_FIRST
; i
<= FNID_SWITCH
; i
++)
545 if (GETPFNSERVER(i
) == Class
->lpfnWndProc
)
548 Ret
= (ULONG_PTR
)GETPFNCLIENTA(i
);
550 Ret
= (ULONG_PTR
)GETPFNCLIENTW(i
);
556 Ret
= (ULONG_PTR
)Class
->lpfnWndProc
;
557 // Return the proc if one of the FnId default class type.
558 if (Class
->fnid
<= FNID_GHOST
&& Class
->fnid
>= FNID_BUTTON
)
561 { // If match return the right proc by type.
562 if (GETPFNCLIENTW(Class
->fnid
) == Class
->lpfnWndProc
)
563 Ret
= (ULONG_PTR
)GETPFNCLIENTA(Class
->fnid
);
567 if (GETPFNCLIENTA(Class
->fnid
) == Class
->lpfnWndProc
)
568 Ret
= (ULONG_PTR
)GETPFNCLIENTW(Class
->fnid
);
571 // Return on change or Ansi/Unicode proc equal.
572 if ( Ret
!= (ULONG_PTR
)Class
->lpfnWndProc
||
573 Ansi
== !!(Class
->CSF_flags
& CSF_ANSIPROC
) )
576 /* We have an Ansi and Unicode swap! If Ansi create Unicode proc handle.
577 This will force CallWindowProc to deal with it. */
578 gcpd
= NtUserGetCPD( UserHMGetHandle(pWnd
),
579 (Ansi
? UserGetCPDA2U
: UserGetCPDU2A
)|UserGetCPDWndtoCls
,
582 return (gcpd
? gcpd
: Ret
);
586 // Based on IntGetClsWndProc
589 IntGetWndProc(PWND pWnd
, BOOL Ansi
)
592 WNDPROC gcpd
, Ret
= 0;
593 PCLS Class
= DesktopPtrToUser(pWnd
->pcls
);
595 if (!Class
) return Ret
;
597 if (pWnd
->state
& WNDS_SERVERSIDEWINDOWPROC
)
599 for ( i
= FNID_FIRST
; i
<= FNID_SWITCH
; i
++)
601 if (GETPFNSERVER(i
) == pWnd
->lpfnWndProc
)
604 Ret
= GETPFNCLIENTA(i
);
606 Ret
= GETPFNCLIENTW(i
);
612 /* Edit controls are special - they return a wndproc handle when
613 GetWindowLongPtr is called with a different A/W.
614 On the other hand there is no W->A->W conversion so this control
615 is treated specially.
617 if (Class
->fnid
== FNID_EDIT
)
618 Ret
= pWnd
->lpfnWndProc
;
622 Ret
= pWnd
->lpfnWndProc
;
624 if (Class
->fnid
<= FNID_GHOST
&& Class
->fnid
>= FNID_BUTTON
)
628 if (GETPFNCLIENTW(Class
->fnid
) == pWnd
->lpfnWndProc
)
629 Ret
= GETPFNCLIENTA(Class
->fnid
);
633 if (GETPFNCLIENTA(Class
->fnid
) == pWnd
->lpfnWndProc
)
634 Ret
= GETPFNCLIENTW(Class
->fnid
);
637 // Return on the change.
638 if ( Ret
!= pWnd
->lpfnWndProc
)
642 if ( Ansi
== !!(pWnd
->state
& WNDS_ANSIWINDOWPROC
) )
645 gcpd
= (WNDPROC
)NtUserGetCPD( UserHMGetHandle(pWnd
),
646 (Ansi
? UserGetCPDA2U
: UserGetCPDU2A
)|UserGetCPDWindow
,
649 return (gcpd
? gcpd
: Ret
);
652 static ULONG_PTR FASTCALL
653 IntGetClassLongA(PWND Wnd
, PCLS Class
, int nIndex
)
659 if (nIndex
+ sizeof(ULONG_PTR
) < nIndex
||
660 nIndex
+ sizeof(ULONG_PTR
) > Class
->cbclsExtra
)
662 SetLastError(ERROR_INVALID_PARAMETER
);
665 Ret
= *(PULONG_PTR
)((ULONG_PTR
)(Class
+ 1) + nIndex
);
672 Ret
= (ULONG_PTR
)Class
->cbwndExtra
;
676 Ret
= (ULONG_PTR
)Class
->cbclsExtra
;
679 case GCL_HBRBACKGROUND
:
680 Ret
= (ULONG_PTR
)Class
->hbrBackground
;
681 if (Ret
!= 0 && Ret
< 0x4000)
682 Ret
= (ULONG_PTR
)GetSysColorBrush((ULONG
)Ret
- 1);
686 //ERR("Cls 0x%x GCL_HMODULE 0x%x\n", Wnd->pcls, Class->hModule);
687 Ret
= (ULONG_PTR
)Class
->hModule
;
691 Ret
= (ULONG_PTR
)Class
->lpszClientAnsiMenuName
;
695 Ret
= (ULONG_PTR
)Class
->style
;
699 Ret
= (ULONG_PTR
)Class
->atomNVClassName
;
703 Ret
= Class
->spcur
? (ULONG_PTR
)((PPROCMARKHEAD
)SharedPtrToUser(Class
->spcur
))->h
: 0;
707 Ret
= Class
->spicn
? (ULONG_PTR
)((PPROCMARKHEAD
)SharedPtrToUser(Class
->spicn
))->h
: 0;
711 Ret
= Class
->spicnSm
? (ULONG_PTR
)((PPROCMARKHEAD
)SharedPtrToUser(Class
->spicnSm
))->h
: 0;
715 Ret
= IntGetClsWndProc(Wnd
, Class
, TRUE
);
719 SetLastError(ERROR_INVALID_INDEX
);
727 static ULONG_PTR FASTCALL
728 IntGetClassLongW (PWND Wnd
, PCLS Class
, int nIndex
)
734 if (nIndex
+ sizeof(ULONG_PTR
) < nIndex
||
735 nIndex
+ sizeof(ULONG_PTR
) > Class
->cbclsExtra
)
737 SetLastError(ERROR_INVALID_PARAMETER
);
740 Ret
= *(PULONG_PTR
)((ULONG_PTR
)(Class
+ 1) + nIndex
);
747 Ret
= (ULONG_PTR
)Class
->cbwndExtra
;
751 Ret
= (ULONG_PTR
)Class
->cbclsExtra
;
754 case GCLP_HBRBACKGROUND
:
755 Ret
= (ULONG_PTR
)Class
->hbrBackground
;
756 if (Ret
!= 0 && Ret
< 0x4000)
757 Ret
= (ULONG_PTR
)GetSysColorBrush((ULONG
)Ret
- 1);
761 Ret
= (ULONG_PTR
)Class
->hModule
;
765 Ret
= (ULONG_PTR
)Class
->lpszClientUnicodeMenuName
;
769 Ret
= (ULONG_PTR
)Class
->style
;
773 Ret
= (ULONG_PTR
)Class
->atomNVClassName
;
777 Ret
= Class
->spcur
? (ULONG_PTR
)((PPROCMARKHEAD
)SharedPtrToUser(Class
->spcur
))->h
: 0;
781 Ret
= Class
->spicn
? (ULONG_PTR
)((PPROCMARKHEAD
)SharedPtrToUser(Class
->spicn
))->h
: 0;
785 Ret
= Class
->spicnSm
? (ULONG_PTR
)((PPROCMARKHEAD
)SharedPtrToUser(Class
->spicnSm
))->h
: 0;
789 Ret
= IntGetClsWndProc(Wnd
, Class
, FALSE
);
793 SetLastError(ERROR_INVALID_INDEX
);
805 GetClassLongA(HWND hWnd
, int nIndex
)
811 TRACE("%p %d\n", hWnd
, nIndex
);
813 Wnd
= ValidateHwnd(hWnd
);
819 Class
= DesktopPtrToUser(Wnd
->pcls
);
825 case GCLP_HBRBACKGROUND
:
832 SetLastError(ERROR_INVALID_INDEX
);
836 Ret
= IntGetClassLongA(Wnd
, Class
, nIndex
);
840 Ret
= IntGetClassLongA(Wnd
, Class
, nIndex
);
845 WARN("Invalid class for hwnd 0x%p!\n", hWnd
);
848 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
861 GetClassLongW ( HWND hWnd
, int nIndex
)
867 TRACE("%p %d\n", hWnd
, nIndex
);
869 Wnd
= ValidateHwnd(hWnd
);
875 Class
= DesktopPtrToUser(Wnd
->pcls
);
881 case GCLP_HBRBACKGROUND
:
888 SetLastError(ERROR_INVALID_INDEX
);
892 Ret
= IntGetClassLongW(Wnd
, Class
, nIndex
);
896 Ret
= IntGetClassLongW(Wnd
, Class
, nIndex
);
901 WARN("Invalid class for hwnd 0x%p!\n", hWnd
);
904 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
919 GetClassLongPtrA(HWND hWnd
,
926 TRACE("%p %d\n", hWnd
, nIndex
);
928 Wnd
= ValidateHwnd(hWnd
);
934 Class
= DesktopPtrToUser(Wnd
->pcls
);
937 Ret
= IntGetClassLongA(Wnd
, Class
, nIndex
);
941 WARN("Invalid class for hwnd 0x%p!\n", hWnd
);
944 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
958 GetClassLongPtrW(HWND hWnd
,
965 TRACE("%p %d\n", hWnd
, nIndex
);
967 Wnd
= ValidateHwnd(hWnd
);
973 Class
= DesktopPtrToUser(Wnd
->pcls
);
976 Ret
= IntGetClassLongW(Wnd
, Class
, nIndex
);
980 WARN("Invalid class for hwnd 0x%p!\n", hWnd
);
983 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1003 WCHAR tmpbuf
[MAX_ATOM_LEN
+ 1];
1006 if (nMaxCount
<= 0) return 0;
1007 if (!GetClassNameW( hWnd
, tmpbuf
, sizeof(tmpbuf
)/sizeof(WCHAR
) )) return 0;
1008 RtlUnicodeToMultiByteN( lpClassName
, nMaxCount
- 1, (PULONG
)&len
, tmpbuf
, strlenW(tmpbuf
) * sizeof(WCHAR
) );
1009 lpClassName
[len
] = 0;
1011 TRACE("%p class/atom: %s/%04x %x\n", hWnd
,
1012 IS_ATOM(lpClassName
) ? NULL
: lpClassName
,
1013 IS_ATOM(lpClassName
) ? lpClassName
: 0,
1030 UNICODE_STRING ClassName
;
1033 RtlInitEmptyUnicodeString(&ClassName
,
1035 nMaxCount
* sizeof(WCHAR
));
1037 Result
= NtUserGetClassName(hWnd
,
1041 TRACE("%p class/atom: %S/%04x %x\n", hWnd
,
1042 IS_ATOM(lpClassName
) ? NULL
: lpClassName
,
1043 IS_ATOM(lpClassName
) ? lpClassName
: 0,
1063 if (offset
< 0) return GetClassLongA( hwnd
, offset
);
1065 Wnd
= ValidateHwnd(hwnd
);
1069 class = DesktopPtrToUser(Wnd
->pcls
);
1070 if (class == NULL
) return 0;
1072 if (offset
<= class->cbclsExtra
- sizeof(WORD
))
1073 memcpy( &retvalue
, (char *)(class + 1) + offset
, sizeof(retvalue
) );
1075 SetLastError( ERROR_INVALID_INDEX
);
1081 LONG_PTR
IntGetWindowLong( HWND hwnd
, INT offset
, UINT size
, BOOL unicode
)
1083 LONG_PTR retvalue
= 0;
1086 if (offset
== GWLP_HWNDPARENT
)
1088 HWND parent
= GetAncestor( hwnd
, GA_PARENT
);
1089 if (parent
== GetDesktopWindow()) parent
= GetWindow( hwnd
, GW_OWNER
);
1090 return (ULONG_PTR
)parent
;
1093 if (!(wndPtr
= ValidateHwnd( hwnd
)))
1095 SetLastError( ERROR_INVALID_WINDOW_HANDLE
);
1099 if (offset
>= 0 && wndPtr
->fnid
!= FNID_DESKTOP
)
1101 if (offset
> (int)(wndPtr
->cbwndExtra
- size
))
1103 WARN("Invalid offset %d\n", offset
);
1104 SetLastError( ERROR_INVALID_INDEX
);
1107 retvalue
= *((LONG_PTR
*)((PCHAR
)(wndPtr
+ 1) + offset
));
1109 /* WINE: special case for dialog window procedure */
1110 //if ((offset == DWLP_DLGPROC) && (size == sizeof(LONG_PTR)) && (wndPtr->flags & WIN_ISDIALOG))
1111 // retvalue = (LONG_PTR)IntGetWndProc( (WNDPROC)retvalue, unicode );
1117 case GWLP_USERDATA
: retvalue
= wndPtr
->dwUserData
; break;
1118 case GWL_STYLE
: retvalue
= wndPtr
->style
; break;
1119 case GWL_EXSTYLE
: retvalue
= wndPtr
->ExStyle
; break;
1120 case GWLP_ID
: retvalue
= wndPtr
->IDMenu
; break;
1121 case GWLP_HINSTANCE
: retvalue
= (ULONG_PTR
)wndPtr
->hModule
; break;
1123 /* -1 is an undocumented case which returns WW* */
1124 /* source: http://www.geoffchappell.com/studies/windows/win32/user32/structs/wnd/index.htm*/
1125 case -1: retvalue
= (ULONG_PTR
)&wndPtr
->ww
; break;
1127 /* We don't have a WW but WND already contains the same fields in the right order, */
1128 /* so we can return a pointer to its first field */
1129 case -1: retvalue
= (ULONG_PTR
)&wndPtr
->state
; break;
1133 if (!TestWindowProcess(wndPtr
))
1135 SetLastError(ERROR_ACCESS_DENIED
);
1138 retvalue
= (ULONG_PTR
)IntGetWndProc(wndPtr
, !unicode
);
1142 WARN("Unknown offset %d\n", offset
);
1143 SetLastError( ERROR_INVALID_INDEX
);
1154 GetWindowLongA ( HWND hWnd
, int nIndex
)
1156 return IntGetWindowLong( hWnd
, nIndex
, sizeof(LONG
), FALSE
);
1164 GetWindowLongW(HWND hWnd
, int nIndex
)
1166 return IntGetWindowLong( hWnd
, nIndex
, sizeof(LONG
), TRUE
);
1175 GetWindowLongPtrA(HWND hWnd
,
1178 return IntGetWindowLong( hWnd
, nIndex
, sizeof(LONG_PTR
), FALSE
);
1186 GetWindowLongPtrW(HWND hWnd
,
1189 return IntGetWindowLong( hWnd
, nIndex
, sizeof(LONG_PTR
), TRUE
);
1199 GetWindowWord(HWND hWnd
, int nIndex
)
1204 case GWLP_HINSTANCE
:
1205 case GWLP_HWNDPARENT
:
1210 WARN("Invalid offset %d\n", nIndex
);
1211 SetLastError( ERROR_INVALID_INDEX
);
1216 return IntGetWindowLong( hWnd
, nIndex
, sizeof(WORD
), FALSE
);
1224 RealGetWindowClassW(
1229 UNICODE_STRING ClassName
;
1231 RtlInitEmptyUnicodeString(&ClassName
,
1233 cchType
* sizeof(WCHAR
));
1235 return NtUserGetClassName(hwnd
,TRUE
,&ClassName
);
1244 RealGetWindowClassA(
1249 WCHAR tmpbuf
[MAX_ATOM_LEN
+ 1];
1252 if ((INT
)cchType
<= 0) return 0;
1253 if (!RealGetWindowClassW( hwnd
, tmpbuf
, sizeof(tmpbuf
)/sizeof(WCHAR
) )) return 0;
1254 RtlUnicodeToMultiByteN( pszType
, cchType
- 1, (PULONG
)&len
, tmpbuf
, strlenW(tmpbuf
) * sizeof(WCHAR
) );
1260 * Create a small icon based on a standard icon
1262 #if 0 // Keep vintage code from revision 18764 by GvG!
1264 CreateSmallIcon(HICON StdIcon
)
1266 HICON SmallIcon
= NULL
;
1269 int SmallIconHeight
;
1270 BITMAP StdBitmapInfo
;
1271 HDC hSourceDc
= NULL
;
1274 HBITMAP OldSourceBitmap
= NULL
;
1275 HBITMAP OldDestBitmap
= NULL
;
1277 SmallInfo
.hbmColor
= NULL
;
1278 SmallInfo
.hbmMask
= NULL
;
1280 /* We need something to work with... */
1281 if (NULL
== StdIcon
)
1286 SmallIconWidth
= GetSystemMetrics(SM_CXSMICON
);
1287 SmallIconHeight
= GetSystemMetrics(SM_CYSMICON
);
1288 if (! GetIconInfo(StdIcon
, &StdInfo
))
1290 ERR("Failed to get icon info for icon 0x%x\n", StdIcon
);
1293 if (! GetObjectW(StdInfo
.hbmMask
, sizeof(BITMAP
), &StdBitmapInfo
))
1295 ERR("Failed to get bitmap info for icon 0x%x bitmap 0x%x\n",
1296 StdIcon
, StdInfo
.hbmColor
);
1299 if (StdBitmapInfo
.bmWidth
== SmallIconWidth
&&
1300 StdBitmapInfo
.bmHeight
== SmallIconHeight
)
1302 /* Icon already has the correct dimensions */
1306 hSourceDc
= CreateCompatibleDC(NULL
);
1307 if (NULL
== hSourceDc
)
1309 ERR("Failed to create source DC\n");
1312 hDestDc
= CreateCompatibleDC(NULL
);
1313 if (NULL
== hDestDc
)
1315 ERR("Failed to create dest DC\n");
1319 OldSourceBitmap
= SelectObject(hSourceDc
, StdInfo
.hbmColor
);
1320 if (NULL
== OldSourceBitmap
)
1322 ERR("Failed to select source color bitmap\n");
1325 SmallInfo
.hbmColor
= CreateCompatibleBitmap(hSourceDc
, SmallIconWidth
,
1327 if (NULL
== SmallInfo
.hbmColor
)
1329 ERR("Failed to create color bitmap\n");
1332 OldDestBitmap
= SelectObject(hDestDc
, SmallInfo
.hbmColor
);
1333 if (NULL
== OldDestBitmap
)
1335 ERR("Failed to select dest color bitmap\n");
1338 if (! StretchBlt(hDestDc
, 0, 0, SmallIconWidth
, SmallIconHeight
,
1339 hSourceDc
, 0, 0, StdBitmapInfo
.bmWidth
,
1340 StdBitmapInfo
.bmHeight
, SRCCOPY
))
1342 ERR("Failed to stretch color bitmap\n");
1346 if (NULL
== SelectObject(hSourceDc
, StdInfo
.hbmMask
))
1348 ERR("Failed to select source mask bitmap\n");
1351 SmallInfo
.hbmMask
= CreateCompatibleBitmap(hSourceDc
, SmallIconWidth
, SmallIconHeight
);
1352 if (NULL
== SmallInfo
.hbmMask
)
1354 ERR("Failed to create mask bitmap\n");
1357 if (NULL
== SelectObject(hDestDc
, SmallInfo
.hbmMask
))
1359 ERR("Failed to select dest mask bitmap\n");
1362 if (! StretchBlt(hDestDc
, 0, 0, SmallIconWidth
, SmallIconHeight
,
1363 hSourceDc
, 0, 0, StdBitmapInfo
.bmWidth
,
1364 StdBitmapInfo
.bmHeight
, SRCCOPY
))
1366 ERR("Failed to stretch mask bitmap\n");
1370 SmallInfo
.fIcon
= TRUE
;
1371 SmallInfo
.xHotspot
= SmallIconWidth
/ 2;
1372 SmallInfo
.yHotspot
= SmallIconHeight
/ 2;
1373 SmallIcon
= CreateIconIndirect(&SmallInfo
);
1374 if (NULL
== SmallIcon
)
1376 ERR("Failed to create icon\n");
1381 if (NULL
!= SmallInfo
.hbmMask
)
1383 DeleteObject(SmallInfo
.hbmMask
);
1385 if (NULL
!= OldDestBitmap
)
1387 SelectObject(hDestDc
, OldDestBitmap
);
1389 if (NULL
!= SmallInfo
.hbmColor
)
1391 DeleteObject(SmallInfo
.hbmColor
);
1393 if (NULL
!= hDestDc
)
1397 if (NULL
!= OldSourceBitmap
)
1399 SelectObject(hSourceDc
, OldSourceBitmap
);
1401 if (NULL
!= hSourceDc
)
1403 DeleteDC(hSourceDc
);
1411 RegisterClassExWOWW(WNDCLASSEXW
*lpwcx
,
1418 WNDCLASSEXW WndClass
;
1419 UNICODE_STRING ClassName
;
1420 UNICODE_STRING ClassVersion
;
1421 UNICODE_STRING MenuName
= {0};
1422 CLSMENUNAME clsMenuName
;
1423 ANSI_STRING AnsiMenuName
;
1424 LPCWSTR lpszClsVersion
;
1426 if (lpwcx
== NULL
|| lpwcx
->cbSize
!= sizeof(WNDCLASSEXW
) ||
1427 lpwcx
->cbClsExtra
< 0 || lpwcx
->cbWndExtra
< 0 ||
1428 lpwcx
->lpszClassName
== NULL
)
1430 TRACE("RegisterClassExWOWW Invalid Parameter Error!\n");
1431 SetLastError(ERROR_INVALID_PARAMETER
);
1437 if (!RegisterDefaultClasses
) RegisterSystemControls();
1440 * On real Windows this looks more like:
1441 * if (lpwcx->hInstance == User32Instance &&
1442 * *(PULONG)((ULONG_PTR)NtCurrentTeb() + 0x6D4) & 0x400)
1443 * But since I have no idea what the magic field in the
1444 * TEB structure means, I rather decided to omit that.
1447 GetWin32ClientInfo()->dwExpWinVer & (WINVER == 0x400)
1449 if (lpwcx
->hInstance
== User32Instance
)
1451 TRACE("RegisterClassExWOWW User32Instance!\n");
1452 SetLastError(ERROR_INVALID_PARAMETER
);
1455 /* Yes, this is correct. We should modify the passed structure. */
1456 if (lpwcx
->hInstance
== NULL
)
1457 ((WNDCLASSEXW
*)lpwcx
)->hInstance
= GetModuleHandleW(NULL
);
1459 RtlCopyMemory(&WndClass
, lpwcx
, sizeof(WNDCLASSEXW
));
1461 if (NULL == WndClass.hIconSm)
1463 WndClass.hIconSm = CreateSmallIcon(WndClass.hIcon);
1466 RtlInitEmptyAnsiString(&AnsiMenuName
, NULL
, 0);
1467 if (WndClass
.lpszMenuName
!= NULL
)
1469 if (!IS_INTRESOURCE(WndClass
.lpszMenuName
))
1471 if (WndClass
.lpszMenuName
[0])
1473 RtlInitUnicodeString(&MenuName
, WndClass
.lpszMenuName
);
1474 RtlUnicodeStringToAnsiString( &AnsiMenuName
, &MenuName
, TRUE
);
1479 MenuName
.Buffer
= (LPWSTR
)WndClass
.lpszMenuName
;
1480 AnsiMenuName
.Buffer
= (PCHAR
)WndClass
.lpszMenuName
;
1484 if (IS_ATOM(WndClass
.lpszClassName
))
1487 ClassName
.MaximumLength
= 0;
1488 ClassName
.Buffer
= (LPWSTR
)WndClass
.lpszClassName
;
1492 RtlInitUnicodeString(&ClassName
, WndClass
.lpszClassName
);
1495 ClassVersion
= ClassName
;
1498 lpszClsVersion
= ClassNameToVersion(lpwcx
->lpszClassName
, NULL
, NULL
, NULL
, FALSE
);
1501 RtlInitUnicodeString(&ClassVersion
, lpszClsVersion
);
1505 clsMenuName
.pszClientAnsiMenuName
= AnsiMenuName
.Buffer
;
1506 clsMenuName
.pwszClientUnicodeMenuName
= MenuName
.Buffer
;
1507 clsMenuName
.pusMenuName
= &MenuName
;
1509 Atom
= NtUserRegisterClassExWOW( &WndClass
,
1517 TRACE("atom=%04x wndproc=%p hinst=%p bg=%p style=%08x clsExt=%d winExt=%d class=%p\n",
1518 Atom
, lpwcx
->lpfnWndProc
, lpwcx
->hInstance
, lpwcx
->hbrBackground
,
1519 lpwcx
->style
, lpwcx
->cbClsExtra
, lpwcx
->cbWndExtra
, WndClass
);
1528 RegisterClassExA(CONST WNDCLASSEXA
*lpwcx
)
1531 WNDCLASSEXW WndClass
;
1532 WCHAR mname
[MAX_BUFFER_LEN
];
1533 WCHAR cname
[MAX_BUFFER_LEN
];
1535 RtlCopyMemory(&WndClass
, lpwcx
, sizeof(WNDCLASSEXA
));
1537 if (WndClass
.lpszMenuName
!= NULL
)
1539 if (!IS_INTRESOURCE(WndClass
.lpszMenuName
))
1541 if (WndClass
.lpszMenuName
[0])
1543 if (!MultiByteToWideChar( CP_ACP
, 0, lpwcx
->lpszMenuName
, -1, mname
, MAX_ATOM_LEN
+ 1 )) return 0;
1545 WndClass
.lpszMenuName
= mname
;
1550 if (!IS_ATOM(WndClass
.lpszClassName
))
1552 if (!MultiByteToWideChar( CP_ACP
, 0, lpwcx
->lpszClassName
, -1, cname
, MAX_ATOM_LEN
+ 1 )) return 0;
1554 WndClass
.lpszClassName
= cname
;
1557 Atom
= RegisterClassExWOWW( &WndClass
,
1563 TRACE("A atom=%04x wndproc=%p hinst=%p bg=%p style=%08x clsExt=%d winExt=%d class=%p\n",
1564 Atom
, lpwcx
->lpfnWndProc
, lpwcx
->hInstance
, lpwcx
->hbrBackground
,
1565 lpwcx
->style
, lpwcx
->cbClsExtra
, lpwcx
->cbWndExtra
, WndClass
);
1574 RegisterClassExW(CONST WNDCLASSEXW
*lpwcx
)
1578 Atom
= RegisterClassExWOWW( (WNDCLASSEXW
*)lpwcx
, 0, 0, 0, TRUE
);
1580 TRACE("W atom=%04x wndproc=%p hinst=%p bg=%p style=%08x clsExt=%d winExt=%d\n",
1581 Atom
, lpwcx
->lpfnWndProc
, lpwcx
->hInstance
, lpwcx
->hbrBackground
,
1582 lpwcx
->style
, lpwcx
->cbClsExtra
, lpwcx
->cbWndExtra
);
1591 RegisterClassA(CONST WNDCLASSA
*lpWndClass
)
1595 if (lpWndClass
== NULL
)
1598 /* These MUST be copied manually, since on 64 bit architectures the
1599 alignment of the members is different between the 2 structs! */
1600 Class
.style
= lpWndClass
->style
;
1601 Class
.lpfnWndProc
= lpWndClass
->lpfnWndProc
;
1602 Class
.cbClsExtra
= lpWndClass
->cbClsExtra
;
1603 Class
.cbWndExtra
= lpWndClass
->cbWndExtra
;
1604 Class
.hInstance
= lpWndClass
->hInstance
;
1605 Class
.hIcon
= lpWndClass
->hIcon
;
1606 Class
.hCursor
= lpWndClass
->hCursor
;
1607 Class
.hbrBackground
= lpWndClass
->hbrBackground
;
1608 Class
.lpszMenuName
= lpWndClass
->lpszMenuName
;
1609 Class
.lpszClassName
= lpWndClass
->lpszClassName
;
1611 Class
.cbSize
= sizeof(WNDCLASSEXA
);
1612 Class
.hIconSm
= NULL
;
1614 return RegisterClassExA(&Class
);
1621 RegisterClassW(CONST WNDCLASSW
*lpWndClass
)
1625 if (lpWndClass
== NULL
)
1628 /* These MUST be copied manually, since on 64 bit architectures the
1629 alignment of the members is different between the 2 structs! */
1630 Class
.style
= lpWndClass
->style
;
1631 Class
.lpfnWndProc
= lpWndClass
->lpfnWndProc
;
1632 Class
.cbClsExtra
= lpWndClass
->cbClsExtra
;
1633 Class
.cbWndExtra
= lpWndClass
->cbWndExtra
;
1634 Class
.hInstance
= lpWndClass
->hInstance
;
1635 Class
.hIcon
= lpWndClass
->hIcon
;
1636 Class
.hCursor
= lpWndClass
->hCursor
;
1637 Class
.hbrBackground
= lpWndClass
->hbrBackground
;
1638 Class
.lpszMenuName
= lpWndClass
->lpszMenuName
;
1639 Class
.lpszClassName
= lpWndClass
->lpszClassName
;
1641 Class
.cbSize
= sizeof(WNDCLASSEXW
);
1642 Class
.hIconSm
= NULL
;
1644 return RegisterClassExW(&Class
);
1652 SetClassLongA (HWND hWnd
,
1656 PSTR lpStr
= (PSTR
)(ULONG_PTR
)dwNewLong
;
1657 UNICODE_STRING Value
= {0};
1658 BOOL Allocated
= FALSE
;
1661 /* FIXME - portability!!!! */
1663 if (nIndex
== GCL_MENUNAME
&& lpStr
!= NULL
)
1665 if (!IS_INTRESOURCE(lpStr
))
1667 if (!RtlCreateUnicodeStringFromAsciiz(&Value
,
1670 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1677 Value
.Buffer
= (PWSTR
)lpStr
;
1679 dwNewLong
= (LONG_PTR
)&Value
;
1681 else if (nIndex
== GCW_ATOM
&& lpStr
!= NULL
)
1683 if (!IS_ATOM(lpStr
))
1685 if (!RtlCreateUnicodeStringFromAsciiz(&Value
,
1688 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1695 Value
.Buffer
= (PWSTR
)lpStr
;
1697 dwNewLong
= (LONG_PTR
)&Value
;
1700 Ret
= (DWORD
)NtUserSetClassLong(hWnd
,
1707 RtlFreeUnicodeString(&Value
);
1719 SetClassLongW(HWND hWnd
,
1723 PWSTR lpStr
= (PWSTR
)(ULONG_PTR
)dwNewLong
;
1724 UNICODE_STRING Value
= {0};
1726 TRACE("%p %d %lx\n", hWnd
, nIndex
, dwNewLong
);
1728 /* FIXME - portability!!!! */
1730 if (nIndex
== GCL_MENUNAME
&& lpStr
!= NULL
)
1732 if (!IS_INTRESOURCE(lpStr
))
1734 RtlInitUnicodeString(&Value
,
1738 Value
.Buffer
= lpStr
;
1740 dwNewLong
= (LONG_PTR
)&Value
;
1742 else if (nIndex
== GCW_ATOM
&& lpStr
!= NULL
)
1744 if (!IS_ATOM(lpStr
))
1746 RtlInitUnicodeString(&Value
,
1750 Value
.Buffer
= lpStr
;
1752 dwNewLong
= (LONG_PTR
)&Value
;
1755 return (DWORD
)NtUserSetClassLong(hWnd
,
1767 SetClassLongPtrA(HWND hWnd
,
1780 SetClassLongPtrW(HWND hWnd
,
1799 * NOTE: Obsoleted in 32-bit windows
1802 if ((nIndex
< 0) && (nIndex
!= GCW_ATOM
))
1805 return (WORD
) SetClassLongW ( hWnd
, nIndex
, wNewWord
);
1813 SetWindowWord ( HWND hWnd
,int nIndex
,WORD wNewWord
)
1818 case GWLP_HINSTANCE
:
1819 case GWLP_HWNDPARENT
:
1824 WARN("Invalid offset %d\n", nIndex
);
1825 SetLastError( ERROR_INVALID_INDEX
);
1830 return NtUserSetWindowLong( hWnd
, nIndex
, wNewWord
, FALSE
);
1844 return NtUserSetWindowLong(hWnd
, nIndex
, dwNewLong
, TRUE
);
1857 return NtUserSetWindowLong(hWnd
, nIndex
, dwNewLong
, FALSE
);
1866 SetWindowLongPtrA(HWND hWnd
,
1870 return NtUserSetWindowLongPtr(hWnd
, nIndex
, dwNewLong
, TRUE
);
1878 SetWindowLongPtrW(HWND hWnd
,
1882 return NtUserSetWindowLongPtr(hWnd
, nIndex
, dwNewLong
, FALSE
);
1893 HINSTANCE hInstance
)
1895 UNICODE_STRING ClassName
= {0};
1897 LPCWSTR lpszClsVersion
;
1898 BOOL ConvertedString
= FALSE
;
1900 TRACE("class/atom: %s/%04x %p\n",
1901 IS_ATOM(lpClassName
) ? NULL
: lpClassName
,
1902 IS_ATOM(lpClassName
) ? lpClassName
: 0,
1905 lpszClsVersion
= ClassNameToVersion(lpClassName
, NULL
, NULL
, NULL
, TRUE
);
1908 RtlInitUnicodeString(&ClassName
, lpszClsVersion
);
1910 else if (!IS_ATOM(lpClassName
))
1912 ConvertedString
= TRUE
;
1913 if (!RtlCreateUnicodeStringFromAsciiz(&ClassName
, lpClassName
))
1915 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1921 ClassName
.Buffer
= (PWSTR
)((ULONG_PTR
)lpClassName
);
1924 Ret
= NtUserUnregisterClass(&ClassName
, hInstance
, 0);
1926 if (ConvertedString
)
1927 RtlFreeUnicodeString(&ClassName
);
1939 LPCWSTR lpClassName
,
1940 HINSTANCE hInstance
)
1942 UNICODE_STRING ClassName
= {0};
1943 LPCWSTR lpszClsVersion
;
1945 TRACE("class/atom: %S/%04x %p\n",
1946 IS_ATOM(lpClassName
) ? NULL
: lpClassName
,
1947 IS_ATOM(lpClassName
) ? lpClassName
: 0,
1950 lpszClsVersion
= ClassNameToVersion(lpClassName
, NULL
, NULL
, NULL
, FALSE
);
1953 RtlInitUnicodeString(&ClassName
, lpszClsVersion
);
1955 else if (!IS_ATOM(lpClassName
))
1957 RtlInitUnicodeString(&ClassName
, lpClassName
);
1961 ClassName
.Buffer
= (PWSTR
)((ULONG_PTR
)lpClassName
);
1964 return NtUserUnregisterClass(&ClassName
, hInstance
, 0);