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