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