xref: /reactos/win32ss/user/user32/windows/class.c (revision cce399e7)
1 /*
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)
7  * UPDATE HISTORY:
8  *      09-05-2001  CSH  Created
9  */
10 
11 #include <user32.h>
12 
13 WINE_DEFAULT_DEBUG_CHANNEL(user32);
14 
15 #define USE_VERSIONED_CLASSES
16 
17 /* From rtl/actctx.c and must match! */
18 struct strsection_header
19 {
20     DWORD magic;
21     ULONG size;
22     DWORD unk1[3];
23     ULONG count;
24     ULONG index_offset;
25     DWORD unk2[2];
26     ULONG global_offset;
27     ULONG global_len;
28 };
29 
30 struct wndclass_redirect_data
31 {
32     ULONG size;
33     DWORD res;
34     ULONG name_len;
35     ULONG name_offset;  /* versioned name offset */
36     ULONG module_len;
37     ULONG module_offset;/* container name offset */
38 };
39 
40 //
41 // Use wine hack to process extended context classes.
42 //
43 /***********************************************************************
44  *           is_comctl32_class
45  */
46 LPCWSTR is_comctl32_class( const WCHAR *name )
47 {
48     static const WCHAR classesW[][20] =
49     {
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},
69     };
70 
71     int min = 0, max = (sizeof(classesW) / sizeof(classesW[0])) - 1;
72 
73     while (min <= max)
74     {
75         int res, pos = (min + max) / 2;
76         if (!(res = strcmpiW( name, classesW[pos] ))) return classesW[pos];
77         if (res < 0) max = pos - 1;
78         else min = pos + 1;
79     }
80     return NULL;
81 }
82 
83 LPCWSTR
84 FASTCALL
85 ClassNameToVersion(
86   const void* lpszClass,
87   LPCWSTR lpszMenuName,
88   LPCWSTR *plpLibFileName,
89   HANDLE *pContext,
90   BOOL bAnsi)
91 {
92     LPCWSTR VersionedClass = NULL;
93 #ifdef USE_VERSIONED_CLASSES
94     NTSTATUS Status;
95 #endif
96     UNICODE_STRING SectionName;
97     WCHAR SectionNameBuf[MAX_PATH] = {0};
98     ACTCTX_SECTION_KEYED_DATA KeyedData = { sizeof(KeyedData) };
99 
100     if (!lpszClass)
101     {
102         ERR("Null class given !\n");
103         return NULL;
104     }
105 
106     if (IS_ATOM(lpszClass))
107     {
108         RtlInitEmptyUnicodeString(&SectionName, SectionNameBuf, sizeof(SectionNameBuf));
109         if(!NtUserGetAtomName(LOWORD((DWORD_PTR)lpszClass), &SectionName))
110         {
111             ERR("Couldn't get atom name for atom %x !\n", LOWORD((DWORD_PTR)lpszClass));
112             return NULL;
113         }
114         SectionName.Length = (USHORT)wcslen(SectionNameBuf) * sizeof(WCHAR);
115         TRACE("ClassNameToVersion got name %wZ from atom\n", &SectionName);
116     }
117     else
118     {
119         if (bAnsi)
120         {
121             ANSI_STRING AnsiString;
122             RtlInitAnsiString(&AnsiString, lpszClass);
123             RtlInitEmptyUnicodeString(&SectionName, SectionNameBuf, sizeof(SectionNameBuf));
124             RtlAnsiStringToUnicodeString(&SectionName, &AnsiString, FALSE);
125         }
126         else
127         {
128             RtlInitUnicodeString(&SectionName, lpszClass);
129         }
130     }
131 #ifdef USE_VERSIONED_CLASSES
132     Status = RtlFindActivationContextSectionString( FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX,
133                                                     NULL,
134                                                     ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION,
135                                                    &SectionName,
136                                                    &KeyedData );
137 
138     if (NT_SUCCESS(Status) && KeyedData.ulDataFormatVersion == 1)
139     {
140         struct strsection_header *SectionHeader = KeyedData.lpSectionBase;
141 
142         /* Find activation context */
143         if(SectionHeader && SectionHeader->count > 0)
144         {
145             struct wndclass_redirect_data *WindowRedirectionData = KeyedData.lpData;
146             if(WindowRedirectionData && WindowRedirectionData->module_len)
147             {
148                 LPCWSTR lpLibFileName;
149 
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);
153 
154                 if (pContext) *pContext = KeyedData.hActCtx;
155                 if (plpLibFileName) *plpLibFileName = lpLibFileName;
156 
157             }
158         }
159     }
160 
161     if (KeyedData.hActCtx)
162         RtlReleaseActivationContext(KeyedData.hActCtx);
163 #endif
164 
165 #ifndef DEFAULT_ACTIVATION_CONTEXTS_SUPPORTED
166     /* This block is a hack! */
167     if (!VersionedClass)
168     {
169         /*
170          * In windows the default activation context always contains comctl32v5
171          * In reactos we don't have a default activation context so we
172          * mimic wine here.
173          */
174         VersionedClass = is_comctl32_class(SectionName.Buffer);
175         if (VersionedClass)
176         {
177             if (pContext) *pContext = 0;
178             if (plpLibFileName) *plpLibFileName = L"comctl32";
179         }
180     }
181 #endif
182 
183     /*
184      * The returned strings are pointers in the activation context and
185      * will get freed when the activation context gets freed
186      */
187     return VersionedClass;
188 }
189 
190 //
191 // Ref: http://yvs-it.blogspot.com/2010/04/initcommoncontrolsex.html
192 //
193 BOOL
194 FASTCALL
195 VersionRegisterClass(
196   PCWSTR pszClass,
197   LPCWSTR lpLibFileName,
198   HANDLE Contex,
199   HMODULE * phLibModule)
200 {
201     BOOL Ret = FALSE;
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 };
207 
208     ERR("VersionRegisterClass: Attempting to call RegisterClassNameW in %S.\n", lpLibFileName);
209 
210     RtlActivateActivationContextUnsafeFast(&Frame, Contex);
211 
212     _SEH2_TRY
213     {
214         hLibModule = LoadLibraryW(lpLibFileName);
215         if (hLibModule)
216         {
217             if ((pRegisterClassNameW = (void*)GetProcAddress(hLibModule, "RegisterClassNameW")))
218             {
219                 if (IS_ATOM(pszClass))
220                 {
221                     RtlInitEmptyUnicodeString(&ClassName, ClassNameBuf, sizeof(ClassNameBuf));
222                     if (!NtUserGetAtomName(LOWORD((DWORD_PTR)pszClass), &ClassName))
223                     {
224                         ERR("Error while verifying ATOM\n");
225                         _SEH2_YIELD(goto Error_Exit);
226                     }
227                     pszClass = ClassName.Buffer;
228                 }
229                 Ret = pRegisterClassNameW(pszClass);
230             }
231             else
232             {
233                 WARN("No RegisterClassNameW PROC\n");
234             }
235         }
236     }
237     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
238     {
239         ERR("Got exception while trying to call RegisterClassNameW!\n");
240     }
241     _SEH2_END
242 
243 Error_Exit:
244     if (Ret || !hLibModule)
245     {
246         if (phLibModule) *phLibModule = hLibModule;
247     }
248     else
249     {
250         DWORD dwLastError = GetLastError();
251         FreeLibrary(hLibModule);
252         SetLastError(dwLastError);
253     }
254 
255     RtlDeactivateActivationContextUnsafeFast(&Frame);
256     return Ret;
257 }
258 
259 /*
260  * @implemented
261  */
262 BOOL
263 WINAPI
264 GetClassInfoExA(
265   HINSTANCE hInstance,
266   LPCSTR lpszClass,
267   LPWNDCLASSEXA lpwcx)
268 {
269     UNICODE_STRING ClassName = {0};
270     LPCSTR pszMenuName;
271     HMODULE hLibModule = NULL;
272     DWORD dwLastError;
273     BOOL Ret, ClassFound = FALSE, ConvertedString = FALSE;
274     LPCWSTR lpszClsVersion;
275     HANDLE pCtx = NULL;
276     LPCWSTR lpLibFileName = NULL;
277 
278     TRACE("%p class/atom: %s/%04x %p\n", hInstance,
279         IS_ATOM(lpszClass) ? NULL : lpszClass,
280         IS_ATOM(lpszClass) ? lpszClass : 0,
281         lpwcx);
282 
283     if (!lpwcx)
284     {
285         SetLastError(ERROR_NOACCESS);
286         return FALSE;
287     }
288 
289     if (hInstance == User32Instance)
290     {
291         hInstance = NULL;
292     }
293 
294     if (lpszClass == NULL)
295     {
296         SetLastError(ERROR_INVALID_PARAMETER);
297         return FALSE;
298     }
299 
300     lpszClsVersion = ClassNameToVersion(lpszClass, NULL, &lpLibFileName, &pCtx, TRUE);
301     if (lpszClsVersion)
302     {
303         RtlInitUnicodeString(&ClassName, lpszClsVersion);
304     }
305     else if (IS_ATOM(lpszClass))
306     {
307         ClassName.Buffer = (PWSTR)((ULONG_PTR)lpszClass);
308     }
309     else
310     {
311         ConvertedString = TRUE;
312         if (!RtlCreateUnicodeStringFromAsciiz(&ClassName, lpszClass))
313         {
314             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
315             return FALSE;
316         }
317     }
318 
319     if (!RegisterDefaultClasses)
320     {
321         TRACE("RegisterSystemControls\n");
322         RegisterSystemControls();
323     }
324 
325     for(;;)
326     {
327         Ret = NtUserGetClassInfo(hInstance,
328                                  &ClassName,
329                                  (LPWNDCLASSEXW)lpwcx,
330                                  (LPWSTR *)&pszMenuName,
331                                  TRUE);
332         if (Ret) break;
333         if (!lpLibFileName) break;
334         if (!ClassFound)
335         {
336             dwLastError = GetLastError();
337             if ( dwLastError == ERROR_CANNOT_FIND_WND_CLASS ||
338                  dwLastError == ERROR_CLASS_DOES_NOT_EXIST )
339             {
340                 ClassFound = VersionRegisterClass(ClassName.Buffer, lpLibFileName, pCtx, &hLibModule);
341                 if (ClassFound) continue;
342             }
343         }
344         if (hLibModule)
345         {
346             dwLastError = GetLastError();
347             FreeLibrary(hLibModule);
348             SetLastError(dwLastError);
349             hLibModule = 0;
350         }
351         break;
352     }
353 
354     if (Ret)
355     {
356         lpwcx->lpszClassName = lpszClass;
357 //       lpwcx->lpszMenuName  = pszMenuName;
358     }
359 
360     if (ConvertedString)
361     {
362         RtlFreeUnicodeString(&ClassName);
363     }
364 
365     return Ret;
366 }
367 
368 
369 /*
370  * @implemented
371  */
372 BOOL
373 WINAPI
374 GetClassInfoExW(
375   HINSTANCE hInstance,
376   LPCWSTR lpszClass,
377   LPWNDCLASSEXW lpwcx)
378 {
379     UNICODE_STRING ClassName = {0};
380     LPWSTR pszMenuName;
381     HMODULE hLibModule = NULL;
382     DWORD dwLastError;
383     BOOL Ret, ClassFound = FALSE;
384     LPCWSTR lpszClsVersion;
385     HANDLE pCtx = NULL;
386     LPCWSTR lpLibFileName = NULL;
387 
388     TRACE("%p class/atom: %S/%04x %p\n", hInstance,
389         IS_ATOM(lpszClass) ? NULL : lpszClass,
390         IS_ATOM(lpszClass) ? lpszClass : 0,
391         lpwcx);
392 
393     /* From wine, for speed only, ReactOS supports the correct return in
394      * Win32k. cbSize is ignored.
395      */
396     if (!lpwcx)
397     {
398        SetLastError( ERROR_NOACCESS );
399        return FALSE;
400     }
401 
402     if (hInstance == User32Instance)
403     {
404         hInstance = NULL;
405     }
406 
407     if (lpszClass == NULL)
408     {
409         SetLastError(ERROR_INVALID_PARAMETER);
410         return FALSE;
411     }
412 
413     lpszClsVersion = ClassNameToVersion(lpszClass, NULL, &lpLibFileName, &pCtx, FALSE);
414     if (lpszClsVersion)
415     {
416         RtlInitUnicodeString(&ClassName, lpszClsVersion);
417     }
418     else if (IS_ATOM(lpszClass))
419     {
420         ClassName.Buffer = (PWSTR)((ULONG_PTR)lpszClass);
421     }
422     else
423     {
424         RtlInitUnicodeString(&ClassName, lpszClass);
425     }
426 
427     if (!RegisterDefaultClasses)
428     {
429        TRACE("RegisterSystemControls\n");
430        RegisterSystemControls();
431     }
432 
433     for(;;)
434     {
435         Ret = NtUserGetClassInfo( hInstance,
436                                  &ClassName,
437                                   lpwcx,
438                                  &pszMenuName,
439                                   FALSE);
440         if (Ret) break;
441         if (!lpLibFileName) break;
442         if (!ClassFound)
443         {
444             dwLastError = GetLastError();
445             if ( dwLastError == ERROR_CANNOT_FIND_WND_CLASS ||
446                  dwLastError == ERROR_CLASS_DOES_NOT_EXIST )
447             {
448                 ClassFound = VersionRegisterClass(ClassName.Buffer, lpLibFileName, pCtx, &hLibModule);
449                 if (ClassFound) continue;
450             }
451         }
452         if (hLibModule)
453         {
454             dwLastError = GetLastError();
455             FreeLibrary(hLibModule);
456             SetLastError(dwLastError);
457             hLibModule = 0;
458         }
459         break;
460     }
461 
462     if (Ret)
463     {
464         lpwcx->lpszClassName = lpszClass;
465 //       lpwcx->lpszMenuName  = pszMenuName;
466     }
467     return Ret;
468 }
469 
470 
471 /*
472  * @implemented
473  */
474 BOOL
475 WINAPI
476 GetClassInfoA(
477   HINSTANCE hInstance,
478   LPCSTR lpClassName,
479   LPWNDCLASSA lpWndClass)
480 {
481     WNDCLASSEXA wcex;
482     BOOL retval;
483 
484     retval = GetClassInfoExA(hInstance, lpClassName, &wcex);
485     if (retval)
486     {
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;
497     }
498 
499     return retval;
500 }
501 
502 /*
503  * @implemented
504  */
505 BOOL
506 WINAPI
507 GetClassInfoW(
508   HINSTANCE hInstance,
509   LPCWSTR lpClassName,
510   LPWNDCLASSW lpWndClass)
511 {
512     WNDCLASSEXW wcex;
513     BOOL retval;
514 
515     retval = GetClassInfoExW(hInstance, lpClassName, &wcex);
516     if (retval)
517     {
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;
528     }
529     return retval;
530 }
531 
532 //
533 // Based on find_winproc... Fixes many whine tests......
534 //
535 ULONG_PTR FASTCALL
536 IntGetClsWndProc(PWND pWnd, PCLS Class, BOOL Ansi)
537 {
538     INT i;
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++)
544         {
545             if (GETPFNSERVER(i) == Class->lpfnWndProc)
546             {
547                 if (Ansi)
548                     Ret = (ULONG_PTR)GETPFNCLIENTA(i);
549                 else
550                     Ret = (ULONG_PTR)GETPFNCLIENTW(i);
551             }
552         }
553          return Ret;
554     }
555     // Set return proc.
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)
559     {
560         if (Ansi)
561         { // If match return the right proc by type.
562             if (GETPFNCLIENTW(Class->fnid) == Class->lpfnWndProc)
563                 Ret = (ULONG_PTR)GETPFNCLIENTA(Class->fnid);
564         }
565         else
566         {
567             if (GETPFNCLIENTA(Class->fnid) == Class->lpfnWndProc)
568                Ret = (ULONG_PTR)GETPFNCLIENTW(Class->fnid);
569         }
570     }
571     // Return on change or Ansi/Unicode proc equal.
572     if ( Ret != (ULONG_PTR)Class->lpfnWndProc ||
573          Ansi == !!(Class->CSF_flags & CSF_ANSIPROC) )
574         return Ret;
575 
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,
580                          Ret);
581 
582     return (gcpd ? gcpd : Ret);
583 }
584 
585 //
586 // Based on IntGetClsWndProc
587 //
588 WNDPROC FASTCALL
589 IntGetWndProc(PWND pWnd, BOOL Ansi)
590 {
591     INT i;
592     WNDPROC gcpd, Ret = 0;
593     PCLS Class = DesktopPtrToUser(pWnd->pcls);
594 
595     if (!Class) return Ret;
596 
597     if (pWnd->state & WNDS_SERVERSIDEWINDOWPROC)
598     {
599         for ( i = FNID_FIRST; i <= FNID_SWITCH; i++)
600         {
601             if (GETPFNSERVER(i) == pWnd->lpfnWndProc)
602             {
603                 if (Ansi)
604                     Ret = GETPFNCLIENTA(i);
605                 else
606                     Ret = GETPFNCLIENTW(i);
607             }
608         }
609         return Ret;
610     }
611     // Wine Class tests:
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.
616      */
617     if (Class->fnid == FNID_EDIT)
618         Ret = pWnd->lpfnWndProc;
619     else
620     {
621         // Set return proc.
622         Ret = pWnd->lpfnWndProc;
623 
624         if (Class->fnid <= FNID_GHOST && Class->fnid >= FNID_BUTTON)
625         {
626             if (Ansi)
627             {
628                 if (GETPFNCLIENTW(Class->fnid) == pWnd->lpfnWndProc)
629                     Ret = GETPFNCLIENTA(Class->fnid);
630             }
631             else
632             {
633                 if (GETPFNCLIENTA(Class->fnid) == pWnd->lpfnWndProc)
634                     Ret = GETPFNCLIENTW(Class->fnid);
635             }
636         }
637         // Return on the change.
638         if ( Ret != pWnd->lpfnWndProc)
639             return Ret;
640     }
641 
642     if ( Ansi == !!(pWnd->state & WNDS_ANSIWINDOWPROC) )
643         return Ret;
644 
645     gcpd = (WNDPROC)NtUserGetCPD( UserHMGetHandle(pWnd),
646                                   (Ansi ? UserGetCPDA2U : UserGetCPDU2A )|UserGetCPDWindow,
647                                   (ULONG_PTR)Ret);
648 
649     return (gcpd ? gcpd : Ret);
650 }
651 
652 static ULONG_PTR FASTCALL
653 IntGetClassLongA(PWND Wnd, PCLS Class, int nIndex)
654 {
655     ULONG_PTR Ret = 0;
656 
657     if (nIndex >= 0)
658     {
659         if (nIndex + sizeof(ULONG_PTR) < nIndex ||
660             nIndex + sizeof(ULONG_PTR) > Class->cbclsExtra)
661         {
662             SetLastError(ERROR_INVALID_PARAMETER);
663         }
664         else
665             Ret = *(PULONG_PTR)((ULONG_PTR)(Class + 1) + nIndex);
666     }
667     else
668     {
669         switch (nIndex)
670         {
671             case GCL_CBWNDEXTRA:
672                 Ret = (ULONG_PTR)Class->cbwndExtra;
673                 break;
674 
675             case GCL_CBCLSEXTRA:
676                 Ret = (ULONG_PTR)Class->cbclsExtra;
677                 break;
678 
679             case GCL_HBRBACKGROUND:
680                 Ret = (ULONG_PTR)Class->hbrBackground;
681                 if (Ret != 0 && Ret < 0x4000)
682                     Ret = (ULONG_PTR)GetSysColorBrush((ULONG)Ret - 1);
683                 break;
684 
685             case GCL_HMODULE:
686                 //ERR("Cls 0x%x GCL_HMODULE 0x%x\n", Wnd->pcls, Class->hModule);
687                 Ret = (ULONG_PTR)Class->hModule;
688                 break;
689 
690             case GCL_MENUNAME:
691                 Ret = (ULONG_PTR)Class->lpszClientAnsiMenuName;
692                 break;
693 
694             case GCL_STYLE:
695                 Ret = (ULONG_PTR)Class->style;
696                 break;
697 
698             case GCW_ATOM:
699                 Ret = (ULONG_PTR)Class->atomNVClassName;
700                 break;
701 
702             case GCLP_HCURSOR:
703                 Ret = Class->spcur ? (ULONG_PTR)((PPROCMARKHEAD)SharedPtrToUser(Class->spcur))->h : 0;
704                 break;
705 
706             case GCLP_HICON:
707                 Ret = Class->spicn ? (ULONG_PTR)((PPROCMARKHEAD)SharedPtrToUser(Class->spicn))->h : 0;
708                 break;
709 
710             case GCLP_HICONSM:
711                 Ret = Class->spicnSm ? (ULONG_PTR)((PPROCMARKHEAD)SharedPtrToUser(Class->spicnSm))->h : 0;
712                 break;
713 
714             case GCLP_WNDPROC:
715                 Ret = IntGetClsWndProc(Wnd, Class, TRUE);
716                 break;
717 
718             default:
719                 SetLastError(ERROR_INVALID_INDEX);
720                 break;
721         }
722     }
723 
724     return Ret;
725 }
726 
727 static ULONG_PTR FASTCALL
728 IntGetClassLongW(PWND Wnd, PCLS Class, int nIndex)
729 {
730     ULONG_PTR Ret = 0;
731 
732     if (nIndex >= 0)
733     {
734         if (nIndex + sizeof(ULONG_PTR) < nIndex ||
735             nIndex + sizeof(ULONG_PTR) > Class->cbclsExtra)
736         {
737             SetLastError(ERROR_INVALID_PARAMETER);
738         }
739         else
740             Ret = *(PULONG_PTR)((ULONG_PTR)(Class + 1) + nIndex);
741     }
742     else
743     {
744         switch (nIndex)
745         {
746             case GCL_CBWNDEXTRA:
747                 Ret = (ULONG_PTR)Class->cbwndExtra;
748                 break;
749 
750             case GCL_CBCLSEXTRA:
751                 Ret = (ULONG_PTR)Class->cbclsExtra;
752                 break;
753 
754             case GCLP_HBRBACKGROUND:
755                 Ret = (ULONG_PTR)Class->hbrBackground;
756                 if (Ret != 0 && Ret < 0x4000)
757                     Ret = (ULONG_PTR)GetSysColorBrush((ULONG)Ret - 1);
758                 break;
759 
760             case GCL_HMODULE:
761                 Ret = (ULONG_PTR)Class->hModule;
762                 break;
763 
764             case GCLP_MENUNAME:
765                 Ret = (ULONG_PTR)Class->lpszClientUnicodeMenuName;
766                 break;
767 
768             case GCL_STYLE:
769                 Ret = (ULONG_PTR)Class->style;
770                 break;
771 
772             case GCW_ATOM:
773                 Ret = (ULONG_PTR)Class->atomNVClassName;
774                 break;
775 
776             case GCLP_HCURSOR:
777                 Ret = Class->spcur ? (ULONG_PTR)((PPROCMARKHEAD)SharedPtrToUser(Class->spcur))->h : 0;
778                 break;
779 
780             case GCLP_HICON:
781                 Ret = Class->spicn ? (ULONG_PTR)((PPROCMARKHEAD)SharedPtrToUser(Class->spicn))->h : 0;
782                 break;
783 
784             case GCLP_HICONSM:
785                 Ret = Class->spicnSm ? (ULONG_PTR)((PPROCMARKHEAD)SharedPtrToUser(Class->spicnSm))->h : 0;
786                 break;
787 
788             case GCLP_WNDPROC:
789                 Ret = IntGetClsWndProc(Wnd, Class, FALSE);
790                 break;
791 
792             default:
793                 SetLastError(ERROR_INVALID_INDEX);
794                 break;
795         }
796     }
797 
798     return Ret;
799 }
800 
801 /*
802  * @implemented
803  */
804 DWORD WINAPI
805 GetClassLongA(HWND hWnd, int nIndex)
806 {
807     PWND Wnd;
808     PCLS Class;
809     ULONG_PTR Ret = 0;
810 
811     TRACE("%p %d\n", hWnd, nIndex);
812 
813     Wnd = ValidateHwnd(hWnd);
814     if (!Wnd)
815         return 0;
816 
817     _SEH2_TRY
818     {
819         Class = DesktopPtrToUser(Wnd->pcls);
820         if (Class != NULL)
821         {
822 #ifdef _WIN64
823             switch (nIndex)
824             {
825                 case GCLP_HBRBACKGROUND:
826                 case GCLP_HCURSOR:
827                 case GCLP_HICON:
828                 case GCLP_HICONSM:
829                 case GCLP_HMODULE:
830                 case GCLP_MENUNAME:
831                 case GCLP_WNDPROC:
832                     SetLastError(ERROR_INVALID_INDEX);
833                     break;
834 
835                 default:
836                     Ret = IntGetClassLongA(Wnd, Class, nIndex);
837                     break;
838             }
839 #else
840             Ret = IntGetClassLongA(Wnd, Class, nIndex);
841 #endif
842         }
843         else
844         {
845             WARN("Invalid class for hwnd 0x%p!\n", hWnd);
846         }
847     }
848     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
849     {
850         Ret = 0;
851     }
852     _SEH2_END;
853 
854     return (DWORD)Ret;
855 }
856 
857 /*
858  * @implemented
859  */
860 DWORD WINAPI
861 GetClassLongW(HWND hWnd, int nIndex)
862 {
863     PWND Wnd;
864     PCLS Class;
865     ULONG_PTR Ret = 0;
866 
867     TRACE("%p %d\n", hWnd, nIndex);
868 
869     Wnd = ValidateHwnd(hWnd);
870     if (!Wnd)
871         return 0;
872 
873     _SEH2_TRY
874     {
875         Class = DesktopPtrToUser(Wnd->pcls);
876         if (Class != NULL)
877         {
878 #ifdef _WIN64
879             switch (nIndex)
880             {
881                 case GCLP_HBRBACKGROUND:
882                 case GCLP_HCURSOR:
883                 case GCLP_HICON:
884                 case GCLP_HICONSM:
885                 case GCLP_HMODULE:
886                 case GCLP_MENUNAME:
887                 case GCLP_WNDPROC:
888                     SetLastError(ERROR_INVALID_INDEX);
889                     break;
890 
891                 default:
892                     Ret = IntGetClassLongW(Wnd, Class, nIndex);
893                     break;
894             }
895 #else
896             Ret = IntGetClassLongW(Wnd, Class, nIndex);
897 #endif
898         }
899         else
900         {
901             WARN("Invalid class for hwnd 0x%p!\n", hWnd);
902         }
903     }
904     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
905     {
906         Ret = 0;
907     }
908     _SEH2_END;
909 
910     return (DWORD)Ret;
911 }
912 
913 #ifdef _WIN64
914 /*
915  * @implemented
916  */
917 ULONG_PTR
918 WINAPI
919 GetClassLongPtrA(HWND hWnd,
920                  INT nIndex)
921 {
922     PWND Wnd;
923     PCLS Class;
924     ULONG_PTR Ret = 0;
925 
926     TRACE("%p %d\n", hWnd, nIndex);
927 
928     Wnd = ValidateHwnd(hWnd);
929     if (!Wnd)
930         return 0;
931 
932     _SEH2_TRY
933     {
934         Class = DesktopPtrToUser(Wnd->pcls);
935         if (Class != NULL)
936         {
937             Ret = IntGetClassLongA(Wnd, Class, nIndex);
938         }
939         else
940         {
941             WARN("Invalid class for hwnd 0x%p!\n", hWnd);
942         }
943     }
944     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
945     {
946         Ret = 0;
947     }
948     _SEH2_END;
949 
950     return Ret;
951 }
952 
953 /*
954  * @implemented
955  */
956 ULONG_PTR
957 WINAPI
958 GetClassLongPtrW(HWND hWnd,
959                  INT nIndex)
960 {
961     PWND Wnd;
962     PCLS Class;
963     ULONG_PTR Ret = 0;
964 
965     TRACE("%p %d\n", hWnd, nIndex);
966 
967     Wnd = ValidateHwnd(hWnd);
968     if (!Wnd)
969         return 0;
970 
971     _SEH2_TRY
972     {
973         Class = DesktopPtrToUser(Wnd->pcls);
974         if (Class != NULL)
975         {
976             Ret = IntGetClassLongW(Wnd, Class, nIndex);
977         }
978         else
979         {
980             WARN("Invalid class for hwnd 0x%p!\n", hWnd);
981         }
982     }
983     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
984     {
985         Ret = 0;
986     }
987     _SEH2_END;
988 
989     return Ret;
990 }
991 #endif
992 
993 
994 /*
995  * @implemented
996  */
997 int WINAPI
998 GetClassNameA(
999   HWND hWnd,
1000   LPSTR lpClassName,
1001   int nMaxCount)
1002 {
1003     WCHAR tmpbuf[MAX_ATOM_LEN + 1];
1004     int len;
1005 
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;
1010 
1011     TRACE("%p class/atom: %s/%04x %x\n", hWnd,
1012         IS_ATOM(lpClassName) ? NULL : lpClassName,
1013         IS_ATOM(lpClassName) ? lpClassName : 0,
1014         nMaxCount);
1015 
1016     return len;
1017 }
1018 
1019 
1020 /*
1021  * @implemented
1022  */
1023 int
1024 WINAPI
1025 GetClassNameW(
1026   HWND hWnd,
1027   LPWSTR lpClassName,
1028   int nMaxCount)
1029 {
1030     UNICODE_STRING ClassName;
1031     int Result;
1032 
1033     RtlInitEmptyUnicodeString(&ClassName,
1034                               lpClassName,
1035                               nMaxCount * sizeof(WCHAR));
1036 
1037     Result = NtUserGetClassName(hWnd,
1038                                 FALSE,
1039                                 &ClassName);
1040 
1041     TRACE("%p class/atom: %S/%04x %x\n", hWnd,
1042         IS_ATOM(lpClassName) ? NULL : lpClassName,
1043         IS_ATOM(lpClassName) ? lpClassName : 0,
1044         nMaxCount);
1045 
1046     return Result;
1047 }
1048 
1049 
1050 /*
1051  * @implemented
1052  */
1053 WORD
1054 WINAPI
1055 GetClassWord(
1056   HWND hwnd,
1057   int offset)
1058 {
1059     PWND Wnd;
1060     PCLS class;
1061     WORD retvalue = 0;
1062 
1063     if (offset < 0) return GetClassLongA( hwnd, offset );
1064 
1065     Wnd = ValidateHwnd(hwnd);
1066     if (!Wnd)
1067         return 0;
1068 
1069     class = DesktopPtrToUser(Wnd->pcls);
1070     if (class == NULL) return 0;
1071 
1072     if (offset <= class->cbclsExtra - sizeof(WORD))
1073         memcpy( &retvalue, (char *)(class + 1) + offset, sizeof(retvalue) );
1074     else
1075         SetLastError( ERROR_INVALID_INDEX );
1076 
1077     return retvalue;
1078 }
1079 
1080 
1081 LONG_PTR IntGetWindowLong( HWND hwnd, INT offset, UINT size, BOOL unicode )
1082 {
1083     LONG_PTR retvalue = 0;
1084     WND *wndPtr;
1085 
1086     if (offset == GWLP_HWNDPARENT)
1087     {
1088         HWND parent = GetAncestor( hwnd, GA_PARENT );
1089         if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
1090         return (ULONG_PTR)parent;
1091     }
1092 
1093     if (!(wndPtr = ValidateHwnd( hwnd )))
1094     {
1095         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1096         return 0;
1097     }
1098 
1099     if (offset >= 0 && wndPtr->fnid != FNID_DESKTOP)
1100     {
1101         if (offset > (int)(wndPtr->cbwndExtra - size))
1102         {
1103             WARN("Invalid offset %d\n", offset );
1104             SetLastError( ERROR_INVALID_INDEX );
1105             return 0;
1106         }
1107         retvalue = *((LONG_PTR *)((PCHAR)(wndPtr + 1) + offset));
1108 
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 );
1112         return retvalue;
1113     }
1114 
1115     switch(offset)
1116     {
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;
1122 #if 0
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;
1126 #else
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;
1130 #endif
1131     case GWLP_WNDPROC:
1132     {
1133         if (!TestWindowProcess(wndPtr))
1134         {
1135             SetLastError(ERROR_ACCESS_DENIED);
1136             retvalue = 0;
1137             ERR("Outside Access and Denied!\n");
1138             break;
1139         }
1140         retvalue = (ULONG_PTR)IntGetWndProc(wndPtr, !unicode);
1141         break;
1142     }
1143     default:
1144         WARN("Unknown offset %d\n", offset );
1145         SetLastError( ERROR_INVALID_INDEX );
1146         break;
1147     }
1148     return retvalue;
1149 
1150 }
1151 /*
1152  * @implemented
1153  */
1154 LONG
1155 WINAPI
1156 GetWindowLongA ( HWND hWnd, int nIndex )
1157 {
1158     return IntGetWindowLong( hWnd, nIndex, sizeof(LONG), FALSE );
1159 }
1160 
1161 /*
1162  * @implemented
1163  */
1164 LONG
1165 WINAPI
1166 GetWindowLongW(HWND hWnd, int nIndex)
1167 {
1168     return IntGetWindowLong( hWnd, nIndex, sizeof(LONG), TRUE );
1169 }
1170 
1171 #ifdef _WIN64
1172 /*
1173  * @implemented
1174  */
1175 LONG_PTR
1176 WINAPI
1177 GetWindowLongPtrA(HWND hWnd,
1178                   INT nIndex)
1179 {
1180     return IntGetWindowLong( hWnd, nIndex, sizeof(LONG_PTR), FALSE );
1181 }
1182 
1183 /*
1184  * @implemented
1185  */
1186 LONG_PTR
1187 WINAPI
1188 GetWindowLongPtrW(HWND hWnd,
1189                   INT nIndex)
1190 {
1191     return IntGetWindowLong( hWnd, nIndex, sizeof(LONG_PTR), TRUE );
1192 
1193 }
1194 #endif // _WIN64
1195 
1196 /*
1197  * @implemented
1198  */
1199 WORD
1200 WINAPI
1201 GetWindowWord(HWND hWnd, int nIndex)
1202 {
1203     switch(nIndex)
1204     {
1205     case GWLP_ID:
1206     case GWLP_HINSTANCE:
1207     case GWLP_HWNDPARENT:
1208         break;
1209     default:
1210         if (nIndex < 0)
1211         {
1212             WARN("Invalid offset %d\n", nIndex );
1213             SetLastError( ERROR_INVALID_INDEX );
1214             return 0;
1215         }
1216         break;
1217     }
1218     return IntGetWindowLong( hWnd, nIndex, sizeof(WORD), FALSE );
1219 }
1220 
1221 /*
1222  * @implemented
1223  */
1224 UINT
1225 WINAPI
1226 RealGetWindowClassW(
1227   HWND  hwnd,
1228   LPWSTR pszType,
1229   UINT  cchType)
1230 {
1231     UNICODE_STRING ClassName;
1232 
1233     RtlInitEmptyUnicodeString(&ClassName,
1234                               pszType,
1235                               cchType * sizeof(WCHAR));
1236 
1237     return NtUserGetClassName(hwnd,TRUE,&ClassName);
1238 }
1239 
1240 
1241 /*
1242  * @implemented
1243  */
1244 UINT
1245 WINAPI
1246 RealGetWindowClassA(
1247   HWND  hwnd,
1248   LPSTR pszType,
1249   UINT  cchType)
1250 {
1251     WCHAR tmpbuf[MAX_ATOM_LEN + 1];
1252     UINT len;
1253 
1254     if ((INT)cchType <= 0) return 0;
1255     if (!RealGetWindowClassW( hwnd, tmpbuf, sizeof(tmpbuf)/sizeof(WCHAR) )) return 0;
1256     RtlUnicodeToMultiByteN( pszType, cchType - 1, (PULONG)&len, tmpbuf, strlenW(tmpbuf) * sizeof(WCHAR) );
1257     pszType[len] = 0;
1258     return len;
1259 }
1260 
1261 ATOM WINAPI
1262 RegisterClassExWOWW(WNDCLASSEXW *lpwcx,
1263                     LPDWORD pdwWowData,
1264                     WORD fnID,
1265                     DWORD dwFlags,
1266                     BOOL ChkRegCls)
1267 {
1268     ATOM Atom;
1269     WNDCLASSEXW WndClass;
1270     UNICODE_STRING ClassName;
1271     UNICODE_STRING ClassVersion;
1272     UNICODE_STRING MenuName = {0};
1273     CLSMENUNAME clsMenuName;
1274     ANSI_STRING AnsiMenuName;
1275     LPCWSTR lpszClsVersion;
1276 
1277     if (lpwcx == NULL || lpwcx->cbSize != sizeof(*lpwcx) ||
1278         lpwcx->cbClsExtra < 0 || lpwcx->cbWndExtra < 0 ||
1279         lpwcx->lpszClassName == NULL)
1280     {
1281         TRACE("RegisterClassExWOWW Invalid Parameter Error!\n");
1282         SetLastError(ERROR_INVALID_PARAMETER);
1283         return 0;
1284     }
1285 
1286     if (ChkRegCls)
1287     {
1288         if (!RegisterDefaultClasses) RegisterSystemControls();
1289     }
1290     /*
1291      * On real Windows this looks more like:
1292      *    if (lpwcx->hInstance == User32Instance &&
1293      *        *(PULONG)((ULONG_PTR)NtCurrentTeb() + 0x6D4) & 0x400)
1294      * But since I have no idea what the magic field in the
1295      * TEB structure means, I rather decided to omit that.
1296      * -- Filip Navara
1297 
1298         GetWin32ClientInfo()->dwExpWinVer & (WINVER == 0x400)
1299      */
1300     if (lpwcx->hInstance == User32Instance)
1301     {
1302         TRACE("RegisterClassExWOWW User32Instance!\n");
1303         SetLastError(ERROR_INVALID_PARAMETER);
1304         return 0;
1305     }
1306     /* Yes, this is correct. We should modify the passed structure. */
1307     if (lpwcx->hInstance == NULL)
1308        ((WNDCLASSEXW*)lpwcx)->hInstance = GetModuleHandleW(NULL);
1309 
1310     RtlCopyMemory(&WndClass, lpwcx, sizeof(*lpwcx));
1311 
1312     RtlInitEmptyAnsiString(&AnsiMenuName, NULL, 0);
1313     if (!IS_INTRESOURCE(WndClass.lpszMenuName))
1314     {
1315         if (WndClass.lpszMenuName[0])
1316         {
1317             RtlInitUnicodeString(&MenuName, WndClass.lpszMenuName);
1318             RtlUnicodeStringToAnsiString(&AnsiMenuName, &MenuName, TRUE);
1319         }
1320     }
1321     else
1322     {
1323         MenuName.Buffer = (LPWSTR)WndClass.lpszMenuName;
1324         AnsiMenuName.Buffer = (PCHAR)WndClass.lpszMenuName;
1325     }
1326 
1327     if (WndClass.lpszClassName && !IS_ATOM(WndClass.lpszClassName))
1328     {
1329         RtlInitUnicodeString(&ClassName, WndClass.lpszClassName);
1330     }
1331     else
1332     {
1333         ClassName.Length = ClassName.MaximumLength = 0;
1334         ClassName.Buffer = (LPWSTR)WndClass.lpszClassName;
1335     }
1336 
1337     ClassVersion = ClassName;
1338     if (fnID == 0)
1339     {
1340         lpszClsVersion = ClassNameToVersion(lpwcx->lpszClassName, NULL, NULL, NULL, FALSE);
1341         if (lpszClsVersion)
1342         {
1343             RtlInitUnicodeString(&ClassVersion, lpszClsVersion);
1344         }
1345     }
1346 
1347     clsMenuName.pszClientAnsiMenuName = AnsiMenuName.Buffer;
1348     clsMenuName.pwszClientUnicodeMenuName = MenuName.Buffer;
1349     clsMenuName.pusMenuName = &MenuName;
1350 
1351     Atom = NtUserRegisterClassExWOW(&WndClass,
1352                                     &ClassName,
1353                                     &ClassVersion,
1354                                     &clsMenuName,
1355                                     fnID,
1356                                     dwFlags,
1357                                     pdwWowData);
1358 
1359     TRACE("atom=%04x wndproc=%p hinst=%p bg=%p style=%08x clsExt=%d winExt=%d class=%p\n",
1360            Atom, lpwcx->lpfnWndProc, lpwcx->hInstance, lpwcx->hbrBackground,
1361            lpwcx->style, lpwcx->cbClsExtra, lpwcx->cbWndExtra, WndClass);
1362 
1363     return Atom;
1364 }
1365 
1366 /*
1367  * @implemented
1368  */
1369 ATOM WINAPI
1370 RegisterClassExA(CONST WNDCLASSEXA *lpwcx)
1371 {
1372     ATOM Atom;
1373     WNDCLASSEXW WndClass;
1374     WCHAR mname[MAX_BUFFER_LEN];
1375     WCHAR cname[MAX_BUFFER_LEN];
1376 
1377     C_ASSERT(sizeof(WndClass) == sizeof(*lpwcx));
1378 
1379     RtlCopyMemory(&WndClass, lpwcx, sizeof(*lpwcx));
1380 
1381     if (WndClass.lpszMenuName && !IS_INTRESOURCE(WndClass.lpszMenuName))
1382     {
1383         if (WndClass.lpszMenuName[0])
1384         {
1385             if (!MultiByteToWideChar(CP_ACP, 0, lpwcx->lpszMenuName, -1, mname, MAX_ATOM_LEN + 1 ))
1386                 return 0;
1387 
1388             WndClass.lpszMenuName = mname;
1389         }
1390     }
1391 
1392     if (WndClass.lpszClassName && !IS_ATOM(WndClass.lpszClassName))
1393     {
1394         if (!MultiByteToWideChar(CP_ACP, 0, lpwcx->lpszClassName, -1, cname, MAX_ATOM_LEN + 1 ))
1395             return 0;
1396 
1397         WndClass.lpszClassName = cname;
1398     }
1399 
1400     Atom = RegisterClassExWOWW(&WndClass,
1401                                NULL,
1402                                0,
1403                                CSF_ANSIPROC,
1404                                TRUE);
1405 
1406     TRACE("A atom=%04x wndproc=%p hinst=%p bg=%p style=%08x clsExt=%d winExt=%d class=%p\n",
1407            Atom, lpwcx->lpfnWndProc, lpwcx->hInstance, lpwcx->hbrBackground,
1408            lpwcx->style, lpwcx->cbClsExtra, lpwcx->cbWndExtra, WndClass);
1409 
1410     return Atom;
1411 }
1412 
1413 /*
1414  * @implemented
1415  */
1416 ATOM WINAPI
1417 RegisterClassExW(CONST WNDCLASSEXW *lpwcx)
1418 {
1419     ATOM Atom;
1420 
1421     Atom = RegisterClassExWOWW((WNDCLASSEXW *)lpwcx, NULL, 0, 0, TRUE);
1422 
1423     TRACE("W atom=%04x wndproc=%p hinst=%p bg=%p style=%08x clsExt=%d winExt=%d\n",
1424           Atom, lpwcx->lpfnWndProc, lpwcx->hInstance, lpwcx->hbrBackground,
1425           lpwcx->style, lpwcx->cbClsExtra, lpwcx->cbWndExtra);
1426 
1427     return Atom;
1428 }
1429 
1430 /*
1431  * @implemented
1432  */
1433 ATOM WINAPI
1434 RegisterClassA(CONST WNDCLASSA *lpWndClass)
1435 {
1436     WNDCLASSEXA Class;
1437 
1438     if (lpWndClass == NULL)
1439         return 0;
1440 
1441     /* These MUST be copied manually, since on 64 bit architectures the
1442        alignment of the members is different between the 2 structs! */
1443     Class.style = lpWndClass->style;
1444     Class.lpfnWndProc = lpWndClass->lpfnWndProc;
1445     Class.cbClsExtra = lpWndClass->cbClsExtra;
1446     Class.cbWndExtra = lpWndClass->cbWndExtra;
1447     Class.hInstance = lpWndClass->hInstance;
1448     Class.hIcon = lpWndClass->hIcon;
1449     Class.hCursor = lpWndClass->hCursor;
1450     Class.hbrBackground = lpWndClass->hbrBackground;
1451     Class.lpszMenuName = lpWndClass->lpszMenuName;
1452     Class.lpszClassName = lpWndClass->lpszClassName;
1453 
1454     Class.cbSize = sizeof(Class);
1455     Class.hIconSm = NULL;
1456 
1457     return RegisterClassExA(&Class);
1458 }
1459 
1460 /*
1461  * @implemented
1462  */
1463 ATOM WINAPI
1464 RegisterClassW(CONST WNDCLASSW *lpWndClass)
1465 {
1466     WNDCLASSEXW Class;
1467 
1468     if (lpWndClass == NULL)
1469         return 0;
1470 
1471     /* These MUST be copied manually, since on 64 bit architectures the
1472        alignment of the members is different between the 2 structs! */
1473     Class.style = lpWndClass->style;
1474     Class.lpfnWndProc = lpWndClass->lpfnWndProc;
1475     Class.cbClsExtra = lpWndClass->cbClsExtra;
1476     Class.cbWndExtra = lpWndClass->cbWndExtra;
1477     Class.hInstance = lpWndClass->hInstance;
1478     Class.hIcon = lpWndClass->hIcon;
1479     Class.hCursor = lpWndClass->hCursor;
1480     Class.hbrBackground = lpWndClass->hbrBackground;
1481     Class.lpszMenuName = lpWndClass->lpszMenuName;
1482     Class.lpszClassName = lpWndClass->lpszClassName;
1483 
1484     Class.cbSize = sizeof(Class);
1485     Class.hIconSm = NULL;
1486 
1487     return RegisterClassExW(&Class);
1488 }
1489 
1490 /*
1491  * @implemented
1492  */
1493 DWORD
1494 WINAPI
1495 SetClassLongA(HWND hWnd,
1496               int nIndex,
1497               LONG dwNewLong)
1498 {
1499     PSTR lpStr = (PSTR)(ULONG_PTR)dwNewLong;
1500     UNICODE_STRING Value = {0};
1501     BOOL Allocated = FALSE;
1502     DWORD Ret;
1503 
1504     /* FIXME - portability!!!! */
1505 
1506     if (nIndex == GCL_MENUNAME && lpStr != NULL)
1507     {
1508         if (!IS_INTRESOURCE(lpStr))
1509         {
1510             if (!RtlCreateUnicodeStringFromAsciiz(&Value, lpStr))
1511             {
1512                 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1513                 return 0;
1514             }
1515 
1516             Allocated = TRUE;
1517         }
1518         else
1519         {
1520             Value.Buffer = (PWSTR)lpStr;
1521         }
1522 
1523         dwNewLong = (LONG_PTR)&Value;
1524     }
1525     else if (nIndex == GCW_ATOM && lpStr != NULL)
1526     {
1527         if (!IS_ATOM(lpStr))
1528         {
1529             if (!RtlCreateUnicodeStringFromAsciiz(&Value, lpStr))
1530             {
1531                 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1532                 return 0;
1533             }
1534 
1535             Allocated = TRUE;
1536         }
1537         else
1538         {
1539             Value.Buffer = (PWSTR)lpStr;
1540         }
1541 
1542         dwNewLong = (LONG_PTR)&Value;
1543     }
1544 
1545     Ret = (DWORD)NtUserSetClassLong(hWnd,
1546                                     nIndex,
1547                                     dwNewLong,
1548                                     TRUE);
1549 
1550     if (Allocated)
1551     {
1552         RtlFreeUnicodeString(&Value);
1553     }
1554 
1555     return Ret;
1556 }
1557 
1558 
1559 /*
1560  * @implemented
1561  */
1562 DWORD
1563 WINAPI
1564 SetClassLongW(HWND hWnd,
1565               int nIndex,
1566               LONG dwNewLong)
1567 {
1568     PWSTR lpStr = (PWSTR)(ULONG_PTR)dwNewLong;
1569     UNICODE_STRING Value = {0};
1570 
1571     TRACE("%p %d %lx\n", hWnd, nIndex, dwNewLong);
1572 
1573     /* FIXME - portability!!!! */
1574 
1575     if (nIndex == GCL_MENUNAME && lpStr != NULL)
1576     {
1577         if (!IS_INTRESOURCE(lpStr))
1578             RtlInitUnicodeString(&Value, lpStr);
1579         else
1580             Value.Buffer = lpStr;
1581 
1582         dwNewLong = (LONG_PTR)&Value;
1583     }
1584     else if (nIndex == GCW_ATOM && lpStr != NULL)
1585     {
1586         if (!IS_ATOM(lpStr))
1587             RtlInitUnicodeString(&Value, lpStr);
1588         else
1589             Value.Buffer = lpStr;
1590 
1591         dwNewLong = (LONG_PTR)&Value;
1592     }
1593 
1594     return (DWORD)NtUserSetClassLong(hWnd,
1595                                      nIndex,
1596                                      dwNewLong,
1597                                      FALSE);
1598 }
1599 
1600 #ifdef _WIN64
1601 /*
1602  * @unimplemented
1603  */
1604 ULONG_PTR
1605 WINAPI
1606 SetClassLongPtrA(HWND hWnd,
1607                  INT nIndex,
1608                  LONG_PTR dwNewLong)
1609 {
1610     UNIMPLEMENTED;
1611     return 0;
1612 }
1613 
1614 /*
1615  * @unimplemented
1616  */
1617 ULONG_PTR
1618 WINAPI
1619 SetClassLongPtrW(HWND hWnd,
1620                  INT nIndex,
1621                  LONG_PTR dwNewLong)
1622 {
1623     UNIMPLEMENTED;
1624     return 0;
1625 }
1626 #endif // _WIN64
1627 
1628 /*
1629  * @implemented
1630  */
1631 WORD
1632 WINAPI
1633 SetClassWord(
1634   HWND hWnd,
1635   int nIndex,
1636   WORD wNewWord)
1637 /*
1638  * NOTE: Obsoleted in 32-bit windows
1639  */
1640 {
1641     if ((nIndex < 0) && (nIndex != GCW_ATOM))
1642         return 0;
1643 
1644     return (WORD) SetClassLongW ( hWnd, nIndex, wNewWord );
1645 }
1646 
1647 /*
1648  * @implemented
1649  */
1650 WORD
1651 WINAPI
1652 SetWindowWord ( HWND hWnd,int nIndex,WORD wNewWord )
1653 {
1654     switch(nIndex)
1655     {
1656     case GWLP_ID:
1657     case GWLP_HINSTANCE:
1658     case GWLP_HWNDPARENT:
1659         break;
1660     default:
1661         if (nIndex < 0)
1662         {
1663             WARN("Invalid offset %d\n", nIndex );
1664             SetLastError( ERROR_INVALID_INDEX );
1665             return 0;
1666         }
1667         break;
1668     }
1669     /* DO NOT USE NtUserSetWindowLong(Ptr)! */
1670     return NtUserSetWindowWord(hWnd, nIndex, wNewWord);
1671 }
1672 
1673 /*
1674  * @implemented
1675  */
1676 LONG
1677 WINAPI
1678 DECLSPEC_HOTPATCH
1679 SetWindowLongA(
1680   HWND hWnd,
1681   int nIndex,
1682   LONG dwNewLong)
1683 {
1684     /* DO NOT USE NtUserSetWindowLongPtr! */
1685     return NtUserSetWindowLong(hWnd, nIndex, dwNewLong, TRUE);
1686 }
1687 
1688 /*
1689  * @implemented
1690  */
1691 LONG
1692 WINAPI
1693 SetWindowLongW(
1694   HWND hWnd,
1695   int nIndex,
1696   LONG dwNewLong)
1697 {
1698     /* DO NOT USE NtUserSetWindowLongPtr! */
1699     return NtUserSetWindowLong(hWnd, nIndex, dwNewLong, FALSE);
1700 }
1701 
1702 #ifdef _WIN64
1703 /*
1704  * @implemented
1705  */
1706 LONG_PTR
1707 WINAPI
1708 SetWindowLongPtrA(HWND hWnd,
1709                   INT nIndex,
1710                   LONG_PTR dwNewLong)
1711 {
1712     return NtUserSetWindowLongPtr(hWnd, nIndex, dwNewLong, TRUE);
1713 }
1714 
1715 /*
1716  * @implemented
1717  */
1718 LONG_PTR
1719 WINAPI
1720 SetWindowLongPtrW(HWND hWnd,
1721                   INT nIndex,
1722                   LONG_PTR dwNewLong)
1723 {
1724     return NtUserSetWindowLongPtr(hWnd, nIndex, dwNewLong, FALSE);
1725 }
1726 #endif
1727 
1728 /*
1729  * @implemented
1730  */
1731 BOOL
1732 WINAPI
1733 UnregisterClassA(
1734   LPCSTR lpClassName,
1735   HINSTANCE hInstance)
1736 {
1737     UNICODE_STRING ClassName = {0};
1738     BOOL Ret;
1739     LPCWSTR lpszClsVersion;
1740     BOOL ConvertedString = FALSE;
1741 
1742     TRACE("class/atom: %s/%04x %p\n",
1743         IS_ATOM(lpClassName) ? NULL : lpClassName,
1744         IS_ATOM(lpClassName) ? lpClassName : 0,
1745         hInstance);
1746 
1747     lpszClsVersion = ClassNameToVersion(lpClassName, NULL, NULL, NULL, TRUE);
1748     if (lpszClsVersion)
1749     {
1750         RtlInitUnicodeString(&ClassName, lpszClsVersion);
1751     }
1752     else if (!IS_ATOM(lpClassName))
1753     {
1754         ConvertedString = TRUE;
1755         if (!RtlCreateUnicodeStringFromAsciiz(&ClassName, lpClassName))
1756         {
1757             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1758             return 0;
1759         }
1760     }
1761     else
1762     {
1763         ClassName.Buffer = (PWSTR)((ULONG_PTR)lpClassName);
1764     }
1765 
1766     Ret = NtUserUnregisterClass(&ClassName, hInstance, 0);
1767 
1768     if (ConvertedString)
1769         RtlFreeUnicodeString(&ClassName);
1770 
1771     return Ret;
1772 }
1773 
1774 /*
1775  * @implemented
1776  */
1777 BOOL
1778 WINAPI
1779 UnregisterClassW(
1780   LPCWSTR lpClassName,
1781   HINSTANCE hInstance)
1782 {
1783     UNICODE_STRING ClassName = {0};
1784     LPCWSTR lpszClsVersion;
1785 
1786     TRACE("class/atom: %S/%04x %p\n",
1787         IS_ATOM(lpClassName) ? NULL : lpClassName,
1788         IS_ATOM(lpClassName) ? lpClassName : 0,
1789         hInstance);
1790 
1791     lpszClsVersion = ClassNameToVersion(lpClassName, NULL, NULL, NULL, FALSE);
1792     if (lpszClsVersion)
1793     {
1794         RtlInitUnicodeString(&ClassName, lpszClsVersion);
1795     }
1796     else if (!IS_ATOM(lpClassName))
1797     {
1798         RtlInitUnicodeString(&ClassName, lpClassName);
1799     }
1800     else
1801     {
1802         ClassName.Buffer = (PWSTR)((ULONG_PTR)lpClassName);
1803     }
1804 
1805     return NtUserUnregisterClass(&ClassName, hInstance, 0);
1806 }
1807 
1808 /* EOF */
1809