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