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