xref: /reactos/win32ss/user/user32/windows/class.c (revision ebaf247c)
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 = 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         }
1138         retvalue = (ULONG_PTR)IntGetWndProc(wndPtr, !unicode);
1139         break;
1140     }
1141     default:
1142         WARN("Unknown offset %d\n", offset );
1143         SetLastError( ERROR_INVALID_INDEX );
1144         break;
1145     }
1146     return retvalue;
1147 
1148 }
1149 /*
1150  * @implemented
1151  */
1152 LONG
1153 WINAPI
1154 GetWindowLongA ( HWND hWnd, int nIndex )
1155 {
1156     return IntGetWindowLong( hWnd, nIndex, sizeof(LONG), FALSE );
1157 }
1158 
1159 /*
1160  * @implemented
1161  */
1162 LONG
1163 WINAPI
1164 GetWindowLongW(HWND hWnd, int nIndex)
1165 {
1166     return IntGetWindowLong( hWnd, nIndex, sizeof(LONG), TRUE );
1167 }
1168 
1169 #ifdef _WIN64
1170 /*
1171  * @implemented
1172  */
1173 LONG_PTR
1174 WINAPI
1175 GetWindowLongPtrA(HWND hWnd,
1176                   INT nIndex)
1177 {
1178     return IntGetWindowLong( hWnd, nIndex, sizeof(LONG_PTR), FALSE );
1179 }
1180 
1181 /*
1182  * @implemented
1183  */
1184 LONG_PTR
1185 WINAPI
1186 GetWindowLongPtrW(HWND hWnd,
1187                   INT nIndex)
1188 {
1189     return IntGetWindowLong( hWnd, nIndex, sizeof(LONG_PTR), TRUE );
1190 
1191 }
1192 #endif // _WIN64
1193 
1194 /*
1195  * @implemented
1196  */
1197 WORD
1198 WINAPI
1199 GetWindowWord(HWND hWnd, int nIndex)
1200 {
1201     switch(nIndex)
1202     {
1203     case GWLP_ID:
1204     case GWLP_HINSTANCE:
1205     case GWLP_HWNDPARENT:
1206         break;
1207     default:
1208         if (nIndex < 0)
1209         {
1210             WARN("Invalid offset %d\n", nIndex );
1211             SetLastError( ERROR_INVALID_INDEX );
1212             return 0;
1213         }
1214         break;
1215     }
1216     return IntGetWindowLong( hWnd, nIndex, sizeof(WORD), FALSE );
1217 }
1218 
1219 /*
1220  * @implemented
1221  */
1222 UINT
1223 WINAPI
1224 RealGetWindowClassW(
1225   HWND  hwnd,
1226   LPWSTR pszType,
1227   UINT  cchType)
1228 {
1229     UNICODE_STRING ClassName;
1230 
1231     RtlInitEmptyUnicodeString(&ClassName,
1232                               pszType,
1233                               cchType * sizeof(WCHAR));
1234 
1235     return NtUserGetClassName(hwnd,TRUE,&ClassName);
1236 }
1237 
1238 
1239 /*
1240  * @implemented
1241  */
1242 UINT
1243 WINAPI
1244 RealGetWindowClassA(
1245   HWND  hwnd,
1246   LPSTR pszType,
1247   UINT  cchType)
1248 {
1249     WCHAR tmpbuf[MAX_ATOM_LEN + 1];
1250     UINT len;
1251 
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) );
1255     pszType[len] = 0;
1256     return len;
1257 }
1258 
1259 /*
1260  * Create a small icon based on a standard icon
1261  */
1262 #if 0 // Keep vintage code from revision 18764 by GvG!
1263 static HICON
1264 CreateSmallIcon(HICON StdIcon)
1265 {
1266     HICON SmallIcon = NULL;
1267     ICONINFO StdInfo;
1268     int SmallIconWidth;
1269     int SmallIconHeight;
1270     BITMAP StdBitmapInfo;
1271     HDC hSourceDc = NULL;
1272     HDC hDestDc = NULL;
1273     ICONINFO SmallInfo;
1274     HBITMAP OldSourceBitmap = NULL;
1275     HBITMAP OldDestBitmap = NULL;
1276 
1277     SmallInfo.hbmColor = NULL;
1278     SmallInfo.hbmMask = NULL;
1279 
1280     /* We need something to work with... */
1281     if (NULL == StdIcon)
1282     {
1283         goto cleanup;
1284     }
1285 
1286     SmallIconWidth = GetSystemMetrics(SM_CXSMICON);
1287     SmallIconHeight = GetSystemMetrics(SM_CYSMICON);
1288     if (! GetIconInfo(StdIcon, &StdInfo))
1289     {
1290         ERR("Failed to get icon info for icon 0x%x\n", StdIcon);
1291         goto cleanup;
1292     }
1293    if (! GetObjectW(StdInfo.hbmMask, sizeof(BITMAP), &StdBitmapInfo))
1294     {
1295         ERR("Failed to get bitmap info for icon 0x%x bitmap 0x%x\n",
1296                 StdIcon, StdInfo.hbmColor);
1297         goto cleanup;
1298     }
1299     if (StdBitmapInfo.bmWidth == SmallIconWidth &&
1300         StdBitmapInfo.bmHeight == SmallIconHeight)
1301     {
1302         /* Icon already has the correct dimensions */
1303         return StdIcon;
1304     }
1305 
1306     hSourceDc = CreateCompatibleDC(NULL);
1307     if (NULL == hSourceDc)
1308     {
1309         ERR("Failed to create source DC\n");
1310         goto cleanup;
1311     }
1312     hDestDc = CreateCompatibleDC(NULL);
1313     if (NULL == hDestDc)
1314     {
1315         ERR("Failed to create dest DC\n");
1316         goto cleanup;
1317     }
1318 
1319     OldSourceBitmap = SelectObject(hSourceDc, StdInfo.hbmColor);
1320     if (NULL == OldSourceBitmap)
1321     {
1322         ERR("Failed to select source color bitmap\n");
1323         goto cleanup;
1324     }
1325     SmallInfo.hbmColor = CreateCompatibleBitmap(hSourceDc, SmallIconWidth,
1326                                                 SmallIconHeight);
1327     if (NULL == SmallInfo.hbmColor)
1328     {
1329         ERR("Failed to create color bitmap\n");
1330         goto cleanup;
1331     }
1332     OldDestBitmap = SelectObject(hDestDc, SmallInfo.hbmColor);
1333     if (NULL == OldDestBitmap)
1334     {
1335         ERR("Failed to select dest color bitmap\n");
1336         goto cleanup;
1337     }
1338     if (! StretchBlt(hDestDc, 0, 0, SmallIconWidth, SmallIconHeight,
1339                      hSourceDc, 0, 0, StdBitmapInfo.bmWidth,
1340                      StdBitmapInfo.bmHeight, SRCCOPY))
1341     {
1342         ERR("Failed to stretch color bitmap\n");
1343         goto cleanup;
1344     }
1345 
1346     if (NULL == SelectObject(hSourceDc, StdInfo.hbmMask))
1347     {
1348         ERR("Failed to select source mask bitmap\n");
1349         goto cleanup;
1350     }
1351     SmallInfo.hbmMask = CreateCompatibleBitmap(hSourceDc, SmallIconWidth, SmallIconHeight);
1352     if (NULL == SmallInfo.hbmMask)
1353     {
1354         ERR("Failed to create mask bitmap\n");
1355         goto cleanup;
1356     }
1357     if (NULL == SelectObject(hDestDc, SmallInfo.hbmMask))
1358     {
1359         ERR("Failed to select dest mask bitmap\n");
1360         goto cleanup;
1361     }
1362     if (! StretchBlt(hDestDc, 0, 0, SmallIconWidth, SmallIconHeight,
1363                      hSourceDc, 0, 0, StdBitmapInfo.bmWidth,
1364                      StdBitmapInfo.bmHeight, SRCCOPY))
1365     {
1366         ERR("Failed to stretch mask bitmap\n");
1367         goto cleanup;
1368     }
1369 
1370     SmallInfo.fIcon = TRUE;
1371     SmallInfo.xHotspot = SmallIconWidth / 2;
1372     SmallInfo.yHotspot = SmallIconHeight / 2;
1373     SmallIcon = CreateIconIndirect(&SmallInfo);
1374     if (NULL == SmallIcon)
1375     {
1376         ERR("Failed to create icon\n");
1377         goto cleanup;
1378     }
1379 
1380 cleanup:
1381     if (NULL != SmallInfo.hbmMask)
1382     {
1383         DeleteObject(SmallInfo.hbmMask);
1384     }
1385     if (NULL != OldDestBitmap)
1386     {
1387         SelectObject(hDestDc, OldDestBitmap);
1388     }
1389     if (NULL != SmallInfo.hbmColor)
1390     {
1391         DeleteObject(SmallInfo.hbmColor);
1392     }
1393     if (NULL != hDestDc)
1394     {
1395         DeleteDC(hDestDc);
1396     }
1397     if (NULL != OldSourceBitmap)
1398     {
1399         SelectObject(hSourceDc, OldSourceBitmap);
1400     }
1401     if (NULL != hSourceDc)
1402     {
1403         DeleteDC(hSourceDc);
1404     }
1405 
1406     return SmallIcon;
1407 }
1408 #endif
1409 
1410 ATOM WINAPI
1411 RegisterClassExWOWW(WNDCLASSEXW *lpwcx,
1412                     LPDWORD pdwWowData,
1413                     WORD fnID,
1414                     DWORD dwFlags,
1415                     BOOL ChkRegCls)
1416 {
1417     ATOM Atom;
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;
1425 
1426     if (lpwcx == NULL || lpwcx->cbSize != sizeof(WNDCLASSEXW) ||
1427         lpwcx->cbClsExtra < 0 || lpwcx->cbWndExtra < 0 ||
1428         lpwcx->lpszClassName == NULL)
1429     {
1430         TRACE("RegisterClassExWOWW Invalid Parameter Error!\n");
1431         SetLastError(ERROR_INVALID_PARAMETER);
1432         return 0;
1433     }
1434 
1435     if (ChkRegCls)
1436     {
1437         if (!RegisterDefaultClasses) RegisterSystemControls();
1438     }
1439     /*
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.
1445      * -- Filip Navara
1446 
1447         GetWin32ClientInfo()->dwExpWinVer & (WINVER == 0x400)
1448      */
1449     if (lpwcx->hInstance == User32Instance)
1450     {
1451         TRACE("RegisterClassExWOWW User32Instance!\n");
1452         SetLastError(ERROR_INVALID_PARAMETER);
1453         return 0;
1454     }
1455     /* Yes, this is correct. We should modify the passed structure. */
1456     if (lpwcx->hInstance == NULL)
1457        ((WNDCLASSEXW*)lpwcx)->hInstance = GetModuleHandleW(NULL);
1458 
1459     RtlCopyMemory(&WndClass, lpwcx, sizeof(WNDCLASSEXW));
1460 /*
1461     if (NULL == WndClass.hIconSm)
1462     {
1463         WndClass.hIconSm = CreateSmallIcon(WndClass.hIcon);
1464     }
1465 */
1466     RtlInitEmptyAnsiString(&AnsiMenuName, NULL, 0);
1467     if (WndClass.lpszMenuName != NULL)
1468     {
1469         if (!IS_INTRESOURCE(WndClass.lpszMenuName))
1470         {
1471             if (WndClass.lpszMenuName[0])
1472             {
1473                RtlInitUnicodeString(&MenuName, WndClass.lpszMenuName);
1474                RtlUnicodeStringToAnsiString( &AnsiMenuName, &MenuName, TRUE);
1475             }
1476         }
1477         else
1478         {
1479             MenuName.Buffer = (LPWSTR)WndClass.lpszMenuName;
1480              AnsiMenuName.Buffer = (PCHAR)WndClass.lpszMenuName;
1481         }
1482     }
1483 
1484     if (IS_ATOM(WndClass.lpszClassName))
1485     {
1486         ClassName.Length =
1487         ClassName.MaximumLength = 0;
1488         ClassName.Buffer = (LPWSTR)WndClass.lpszClassName;
1489     }
1490     else
1491     {
1492         RtlInitUnicodeString(&ClassName, WndClass.lpszClassName);
1493     }
1494 
1495     ClassVersion = ClassName;
1496     if (fnID == 0)
1497     {
1498         lpszClsVersion = ClassNameToVersion(lpwcx->lpszClassName, NULL, NULL, NULL, FALSE);
1499         if (lpszClsVersion)
1500         {
1501             RtlInitUnicodeString(&ClassVersion, lpszClsVersion);
1502         }
1503     }
1504 
1505     clsMenuName.pszClientAnsiMenuName = AnsiMenuName.Buffer;
1506     clsMenuName.pwszClientUnicodeMenuName = MenuName.Buffer;
1507     clsMenuName.pusMenuName = &MenuName;
1508 
1509     Atom = NtUserRegisterClassExWOW( &WndClass,
1510                                      &ClassName,
1511                                      &ClassVersion,
1512                                      &clsMenuName,
1513                                      fnID,
1514                                      dwFlags,
1515                                      pdwWowData);
1516 
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);
1520 
1521     return Atom;
1522 }
1523 
1524 /*
1525  * @implemented
1526  */
1527 ATOM WINAPI
1528 RegisterClassExA(CONST WNDCLASSEXA *lpwcx)
1529 {
1530     RTL_ATOM Atom;
1531     WNDCLASSEXW WndClass;
1532     WCHAR mname[MAX_BUFFER_LEN];
1533     WCHAR cname[MAX_BUFFER_LEN];
1534 
1535     RtlCopyMemory(&WndClass, lpwcx, sizeof(WNDCLASSEXA));
1536 
1537     if (WndClass.lpszMenuName != NULL)
1538     {
1539         if (!IS_INTRESOURCE(WndClass.lpszMenuName))
1540         {
1541             if (WndClass.lpszMenuName[0])
1542             {
1543                 if (!MultiByteToWideChar( CP_ACP, 0, lpwcx->lpszMenuName, -1, mname, MAX_ATOM_LEN + 1 )) return 0;
1544 
1545                 WndClass.lpszMenuName = mname;
1546             }
1547         }
1548     }
1549 
1550     if (!IS_ATOM(WndClass.lpszClassName))
1551     {
1552         if (!MultiByteToWideChar( CP_ACP, 0, lpwcx->lpszClassName, -1, cname, MAX_ATOM_LEN + 1 )) return 0;
1553 
1554         WndClass.lpszClassName = cname;
1555     }
1556 
1557     Atom = RegisterClassExWOWW( &WndClass,
1558                                 0,
1559                                 0,
1560                                 CSF_ANSIPROC,
1561                                 TRUE);
1562 
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);
1566 
1567     return (ATOM)Atom;
1568 }
1569 
1570 /*
1571  * @implemented
1572  */
1573 ATOM WINAPI
1574 RegisterClassExW(CONST WNDCLASSEXW *lpwcx)
1575 {
1576     ATOM Atom;
1577 
1578     Atom = RegisterClassExWOWW( (WNDCLASSEXW *)lpwcx, 0, 0, 0, TRUE);
1579 
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);
1583 
1584     return Atom;
1585 }
1586 
1587 /*
1588  * @implemented
1589  */
1590 ATOM WINAPI
1591 RegisterClassA(CONST WNDCLASSA *lpWndClass)
1592 {
1593     WNDCLASSEXA Class;
1594 
1595     if (lpWndClass == NULL)
1596         return 0;
1597 
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;
1610 
1611     Class.cbSize = sizeof(WNDCLASSEXA);
1612     Class.hIconSm = NULL;
1613 
1614     return RegisterClassExA(&Class);
1615 }
1616 
1617 /*
1618  * @implemented
1619  */
1620 ATOM WINAPI
1621 RegisterClassW(CONST WNDCLASSW *lpWndClass)
1622 {
1623     WNDCLASSEXW Class;
1624 
1625     if (lpWndClass == NULL)
1626         return 0;
1627 
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;
1640 
1641     Class.cbSize = sizeof(WNDCLASSEXW);
1642     Class.hIconSm = NULL;
1643 
1644     return RegisterClassExW(&Class);
1645 }
1646 
1647 /*
1648  * @implemented
1649  */
1650 DWORD
1651 WINAPI
1652 SetClassLongA (HWND hWnd,
1653                int nIndex,
1654                LONG dwNewLong)
1655 {
1656     PSTR lpStr = (PSTR)(ULONG_PTR)dwNewLong;
1657     UNICODE_STRING Value = {0};
1658     BOOL Allocated = FALSE;
1659     DWORD Ret;
1660 
1661     /* FIXME - portability!!!! */
1662 
1663     if (nIndex == GCL_MENUNAME && lpStr != NULL)
1664     {
1665         if (!IS_INTRESOURCE(lpStr))
1666         {
1667             if (!RtlCreateUnicodeStringFromAsciiz(&Value,
1668                                                   lpStr))
1669             {
1670                 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1671                 return 0;
1672             }
1673 
1674             Allocated = TRUE;
1675         }
1676         else
1677             Value.Buffer = (PWSTR)lpStr;
1678 
1679         dwNewLong = (LONG_PTR)&Value;
1680     }
1681     else if (nIndex == GCW_ATOM && lpStr != NULL)
1682     {
1683         if (!IS_ATOM(lpStr))
1684         {
1685             if (!RtlCreateUnicodeStringFromAsciiz(&Value,
1686                                                   lpStr))
1687             {
1688                 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1689                 return 0;
1690             }
1691 
1692             Allocated = TRUE;
1693         }
1694         else
1695             Value.Buffer = (PWSTR)lpStr;
1696 
1697         dwNewLong = (LONG_PTR)&Value;
1698     }
1699 
1700     Ret = (DWORD)NtUserSetClassLong(hWnd,
1701                                     nIndex,
1702                                     dwNewLong,
1703                                     TRUE);
1704 
1705     if (Allocated)
1706     {
1707         RtlFreeUnicodeString(&Value);
1708     }
1709 
1710     return Ret;
1711 }
1712 
1713 
1714 /*
1715  * @implemented
1716  */
1717 DWORD
1718 WINAPI
1719 SetClassLongW(HWND hWnd,
1720               int nIndex,
1721               LONG dwNewLong)
1722 {
1723     PWSTR lpStr = (PWSTR)(ULONG_PTR)dwNewLong;
1724     UNICODE_STRING Value = {0};
1725 
1726     TRACE("%p %d %lx\n", hWnd, nIndex, dwNewLong);
1727 
1728     /* FIXME - portability!!!! */
1729 
1730     if (nIndex == GCL_MENUNAME && lpStr != NULL)
1731     {
1732         if (!IS_INTRESOURCE(lpStr))
1733         {
1734             RtlInitUnicodeString(&Value,
1735                                  lpStr);
1736         }
1737         else
1738             Value.Buffer = lpStr;
1739 
1740         dwNewLong = (LONG_PTR)&Value;
1741     }
1742     else if (nIndex == GCW_ATOM && lpStr != NULL)
1743     {
1744         if (!IS_ATOM(lpStr))
1745         {
1746             RtlInitUnicodeString(&Value,
1747                                  lpStr);
1748         }
1749         else
1750             Value.Buffer = lpStr;
1751 
1752         dwNewLong = (LONG_PTR)&Value;
1753     }
1754 
1755     return (DWORD)NtUserSetClassLong(hWnd,
1756                                      nIndex,
1757                                      dwNewLong,
1758                                      FALSE);
1759 }
1760 
1761 #ifdef _WIN64
1762 /*
1763  * @unimplemented
1764  */
1765 ULONG_PTR
1766 WINAPI
1767 SetClassLongPtrA(HWND hWnd,
1768                  INT nIndex,
1769                  LONG_PTR dwNewLong)
1770 {
1771     UNIMPLEMENTED;
1772     return 0;
1773 }
1774 
1775 /*
1776  * @unimplemented
1777  */
1778 ULONG_PTR
1779 WINAPI
1780 SetClassLongPtrW(HWND hWnd,
1781                  INT nIndex,
1782                  LONG_PTR dwNewLong)
1783 {
1784     UNIMPLEMENTED;
1785     return 0;
1786 }
1787 #endif // _WIN64
1788 
1789 /*
1790  * @implemented
1791  */
1792 WORD
1793 WINAPI
1794 SetClassWord(
1795   HWND hWnd,
1796   int nIndex,
1797   WORD wNewWord)
1798 /*
1799  * NOTE: Obsoleted in 32-bit windows
1800  */
1801 {
1802     if ((nIndex < 0) && (nIndex != GCW_ATOM))
1803         return 0;
1804 
1805     return (WORD) SetClassLongW ( hWnd, nIndex, wNewWord );
1806 }
1807 
1808 /*
1809  * @implemented
1810  */
1811 WORD
1812 WINAPI
1813 SetWindowWord ( HWND hWnd,int nIndex,WORD wNewWord )
1814 {
1815     switch(nIndex)
1816     {
1817     case GWLP_ID:
1818     case GWLP_HINSTANCE:
1819     case GWLP_HWNDPARENT:
1820         break;
1821     default:
1822         if (nIndex < 0)
1823         {
1824             WARN("Invalid offset %d\n", nIndex );
1825             SetLastError( ERROR_INVALID_INDEX );
1826             return 0;
1827         }
1828         break;
1829     }
1830     return NtUserSetWindowLong( hWnd, nIndex, wNewWord, FALSE );
1831 }
1832 
1833 /*
1834  * @implemented
1835  */
1836 LONG
1837 WINAPI
1838 DECLSPEC_HOTPATCH
1839 SetWindowLongA(
1840   HWND hWnd,
1841   int nIndex,
1842   LONG dwNewLong)
1843 {
1844     return NtUserSetWindowLong(hWnd, nIndex, dwNewLong, TRUE);
1845 }
1846 
1847 /*
1848  * @implemented
1849  */
1850 LONG
1851 WINAPI
1852 SetWindowLongW(
1853   HWND hWnd,
1854   int nIndex,
1855   LONG dwNewLong)
1856 {
1857     return NtUserSetWindowLong(hWnd, nIndex, dwNewLong, FALSE);
1858 }
1859 
1860 #ifdef _WIN64
1861 /*
1862  * @implemented
1863  */
1864 LONG_PTR
1865 WINAPI
1866 SetWindowLongPtrA(HWND hWnd,
1867                   INT nIndex,
1868                   LONG_PTR dwNewLong)
1869 {
1870     return NtUserSetWindowLongPtr(hWnd, nIndex, dwNewLong, TRUE);
1871 }
1872 
1873 /*
1874  * @implemented
1875  */
1876 LONG_PTR
1877 WINAPI
1878 SetWindowLongPtrW(HWND hWnd,
1879                   INT nIndex,
1880                   LONG_PTR dwNewLong)
1881 {
1882     return NtUserSetWindowLongPtr(hWnd, nIndex, dwNewLong, FALSE);
1883 }
1884 #endif
1885 
1886 /*
1887  * @implemented
1888  */
1889 BOOL
1890 WINAPI
1891 UnregisterClassA(
1892   LPCSTR lpClassName,
1893   HINSTANCE hInstance)
1894 {
1895     UNICODE_STRING ClassName = {0};
1896     BOOL Ret;
1897     LPCWSTR lpszClsVersion;
1898     BOOL ConvertedString = FALSE;
1899 
1900     TRACE("class/atom: %s/%04x %p\n",
1901         IS_ATOM(lpClassName) ? NULL : lpClassName,
1902         IS_ATOM(lpClassName) ? lpClassName : 0,
1903         hInstance);
1904 
1905     lpszClsVersion = ClassNameToVersion(lpClassName, NULL, NULL, NULL, TRUE);
1906     if (lpszClsVersion)
1907     {
1908         RtlInitUnicodeString(&ClassName, lpszClsVersion);
1909     }
1910     else if (!IS_ATOM(lpClassName))
1911     {
1912         ConvertedString = TRUE;
1913         if (!RtlCreateUnicodeStringFromAsciiz(&ClassName, lpClassName))
1914         {
1915             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1916             return 0;
1917         }
1918     }
1919     else
1920     {
1921         ClassName.Buffer = (PWSTR)((ULONG_PTR)lpClassName);
1922     }
1923 
1924     Ret = NtUserUnregisterClass(&ClassName, hInstance, 0);
1925 
1926     if (ConvertedString)
1927         RtlFreeUnicodeString(&ClassName);
1928 
1929     return Ret;
1930 }
1931 
1932 
1933 /*
1934  * @implemented
1935  */
1936 BOOL
1937 WINAPI
1938 UnregisterClassW(
1939   LPCWSTR lpClassName,
1940   HINSTANCE hInstance)
1941 {
1942     UNICODE_STRING ClassName = {0};
1943     LPCWSTR lpszClsVersion;
1944 
1945     TRACE("class/atom: %S/%04x %p\n",
1946         IS_ATOM(lpClassName) ? NULL : lpClassName,
1947         IS_ATOM(lpClassName) ? lpClassName : 0,
1948         hInstance);
1949 
1950     lpszClsVersion = ClassNameToVersion(lpClassName, NULL, NULL, NULL, FALSE);
1951     if (lpszClsVersion)
1952     {
1953         RtlInitUnicodeString(&ClassName, lpszClsVersion);
1954     }
1955     else if (!IS_ATOM(lpClassName))
1956     {
1957         RtlInitUnicodeString(&ClassName, lpClassName);
1958     }
1959     else
1960     {
1961         ClassName.Buffer = (PWSTR)((ULONG_PTR)lpClassName);
1962     }
1963 
1964     return NtUserUnregisterClass(&ClassName, hInstance, 0);
1965 }
1966 
1967 /* EOF */
1968