* Sync up to trunk head (r64921).
[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 #ifdef NEW_CURSORICON
716 case GCLP_HCURSOR:
717 Ret = Class->spcur ? (ULONG_PTR)((PPROCMARKHEAD)SharedPtrToUser(Class->spcur))->h : 0;
718 break;
719
720 case GCLP_HICON:
721 Ret = Class->spicn ? (ULONG_PTR)((PPROCMARKHEAD)SharedPtrToUser(Class->spicn))->h : 0;
722 break;
723
724 case GCLP_HICONSM:
725 Ret = Class->spicnSm ? (ULONG_PTR)((PPROCMARKHEAD)SharedPtrToUser(Class->spicnSm))->h : 0;
726 break;
727 #else
728 case GCLP_HCURSOR:
729 /* FIXME - get handle from pointer to CURSOR object */
730 Ret = (ULONG_PTR)Class->hCursor;
731 break;
732
733 case GCLP_HICON:
734 /* FIXME - get handle from pointer to ICON object */
735 Ret = (ULONG_PTR)Class->hIcon;
736 break;
737
738 case GCLP_HICONSM:
739 /* FIXME - get handle from pointer to ICON object */
740 Ret = (ULONG_PTR)(Class->hIconSm ? Class->hIconSm : Class->hIconSmIntern);
741 break;
742 #endif
743
744 case GCLP_WNDPROC:
745 Ret = IntGetClsWndProc(Wnd, Class, TRUE);
746 break;
747
748 default:
749 SetLastError(ERROR_INVALID_INDEX);
750 break;
751 }
752 }
753
754 return Ret;
755 }
756
757 static ULONG_PTR FASTCALL
758 IntGetClassLongW (PWND Wnd, PCLS Class, int nIndex)
759 {
760 ULONG_PTR Ret = 0;
761
762 if (nIndex >= 0)
763 {
764 if (nIndex + sizeof(ULONG_PTR) < nIndex ||
765 nIndex + sizeof(ULONG_PTR) > Class->cbclsExtra)
766 {
767 SetLastError(ERROR_INVALID_PARAMETER);
768 }
769 else
770 Ret = *(PULONG_PTR)((ULONG_PTR)(Class + 1) + nIndex);
771 }
772 else
773 {
774 switch (nIndex)
775 {
776 case GCL_CBWNDEXTRA:
777 Ret = (ULONG_PTR)Class->cbwndExtra;
778 break;
779
780 case GCL_CBCLSEXTRA:
781 Ret = (ULONG_PTR)Class->cbclsExtra;
782 break;
783
784 case GCLP_HBRBACKGROUND:
785 Ret = (ULONG_PTR)Class->hbrBackground;
786 if (Ret != 0 && Ret < 0x4000)
787 Ret = (ULONG_PTR)GetSysColorBrush((ULONG)Ret - 1);
788 break;
789
790 case GCL_HMODULE:
791 Ret = (ULONG_PTR)Class->hModule;
792 break;
793
794 case GCLP_MENUNAME:
795 Ret = (ULONG_PTR)Class->lpszClientUnicodeMenuName;
796 break;
797
798 case GCL_STYLE:
799 Ret = (ULONG_PTR)Class->style;
800 break;
801
802 case GCW_ATOM:
803 Ret = (ULONG_PTR)Class->atomClassName;
804 break;
805
806 #ifdef NEW_CURSORICON
807 case GCLP_HCURSOR:
808 Ret = Class->spcur ? (ULONG_PTR)((PPROCMARKHEAD)SharedPtrToUser(Class->spcur))->h : 0;
809 break;
810
811 case GCLP_HICON:
812 Ret = Class->spicn ? (ULONG_PTR)((PPROCMARKHEAD)SharedPtrToUser(Class->spicn))->h : 0;
813 break;
814
815 case GCLP_HICONSM:
816 Ret = Class->spicnSm ? (ULONG_PTR)((PPROCMARKHEAD)SharedPtrToUser(Class->spicnSm))->h : 0;
817 break;
818 #else
819 case GCLP_HCURSOR:
820 /* FIXME - get handle from pointer to CURSOR object */
821 Ret = (ULONG_PTR)Class->hCursor;
822 break;
823
824 case GCLP_HICON:
825 /* FIXME - get handle from pointer to ICON object */
826 Ret = (ULONG_PTR)Class->hIcon;
827 break;
828
829 case GCLP_HICONSM:
830 /* FIXME - get handle from pointer to ICON object */
831 Ret = (ULONG_PTR)(Class->hIconSm ? Class->hIconSm : Class->hIconSmIntern);
832 break;
833 #endif
834
835 case GCLP_WNDPROC:
836 Ret = IntGetClsWndProc(Wnd, Class, FALSE);
837 break;
838
839 default:
840 SetLastError(ERROR_INVALID_INDEX);
841 break;
842 }
843 }
844
845 return Ret;
846 }
847
848 /*
849 * @implemented
850 */
851 DWORD WINAPI
852 GetClassLongA(HWND hWnd, int nIndex)
853 {
854 PWND Wnd;
855 PCLS Class;
856 ULONG_PTR Ret = 0;
857
858 TRACE("%p %d\n", hWnd, nIndex);
859
860 Wnd = ValidateHwnd(hWnd);
861 if (!Wnd)
862 return 0;
863
864 _SEH2_TRY
865 {
866 Class = DesktopPtrToUser(Wnd->pcls);
867 if (Class != NULL)
868 {
869 #ifdef _WIN64
870 switch (nIndex)
871 {
872 case GCLP_HBRBACKGROUND:
873 case GCLP_HCURSOR:
874 case GCLP_HICON:
875 case GCLP_HICONSM:
876 case GCLP_HMODULE:
877 case GCLP_MENUNAME:
878 case GCLP_WNDPROC:
879 SetLastError(ERROR_INVALID_INDEX);
880 break;
881
882 default:
883 Ret = IntGetClassLongA(Wnd, Class, nIndex);
884 break;
885 }
886 #else
887 Ret = IntGetClassLongA(Wnd, Class, nIndex);
888 #endif
889 }
890 else
891 {
892 WARN("Invalid class for hwnd 0x%p!\n", hWnd);
893 }
894 }
895 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
896 {
897 Ret = 0;
898 }
899 _SEH2_END;
900
901 return (DWORD)Ret;
902 }
903
904 /*
905 * @implemented
906 */
907 DWORD WINAPI
908 GetClassLongW ( HWND hWnd, int nIndex )
909 {
910 PWND Wnd;
911 PCLS Class;
912 ULONG_PTR Ret = 0;
913
914 TRACE("%p %d\n", hWnd, nIndex);
915
916 Wnd = ValidateHwnd(hWnd);
917 if (!Wnd)
918 return 0;
919
920 _SEH2_TRY
921 {
922 Class = DesktopPtrToUser(Wnd->pcls);
923 if (Class != NULL)
924 {
925 #ifdef _WIN64
926 switch (nIndex)
927 {
928 case GCLP_HBRBACKGROUND:
929 case GCLP_HCURSOR:
930 case GCLP_HICON:
931 case GCLP_HICONSM:
932 case GCLP_HMODULE:
933 case GCLP_MENUNAME:
934 case GCLP_WNDPROC:
935 SetLastError(ERROR_INVALID_INDEX);
936 break;
937
938 default:
939 Ret = IntGetClassLongW(Wnd, Class, nIndex);
940 break;
941 }
942 #else
943 Ret = IntGetClassLongW(Wnd, Class, nIndex);
944 #endif
945 }
946 else
947 {
948 WARN("Invalid class for hwnd 0x%p!\n", hWnd);
949 }
950 }
951 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
952 {
953 Ret = 0;
954 }
955 _SEH2_END;
956
957 return (DWORD)Ret;
958 }
959
960 #ifdef _WIN64
961 /*
962 * @implemented
963 */
964 ULONG_PTR
965 WINAPI
966 GetClassLongPtrA(HWND hWnd,
967 INT nIndex)
968 {
969 PWND Wnd;
970 PCLS Class;
971 ULONG_PTR Ret = 0;
972
973 TRACE("%p %d\n", hWnd, nIndex);
974
975 Wnd = ValidateHwnd(hWnd);
976 if (!Wnd)
977 return 0;
978
979 _SEH2_TRY
980 {
981 Class = DesktopPtrToUser(Wnd->pcls);
982 if (Class != NULL)
983 {
984 Ret = IntGetClassLongA(Wnd, Class, nIndex);
985 }
986 else
987 {
988 WARN("Invalid class for hwnd 0x%p!\n", hWnd);
989 }
990 }
991 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
992 {
993 Ret = 0;
994 }
995 _SEH2_END;
996
997 return Ret;
998 }
999
1000 /*
1001 * @implemented
1002 */
1003 ULONG_PTR
1004 WINAPI
1005 GetClassLongPtrW(HWND hWnd,
1006 INT nIndex)
1007 {
1008 PWND Wnd;
1009 PCLS Class;
1010 ULONG_PTR Ret = 0;
1011
1012 TRACE("%p %d\n", hWnd, nIndex);
1013
1014 Wnd = ValidateHwnd(hWnd);
1015 if (!Wnd)
1016 return 0;
1017
1018 _SEH2_TRY
1019 {
1020 Class = DesktopPtrToUser(Wnd->pcls);
1021 if (Class != NULL)
1022 {
1023 Ret = IntGetClassLongW(Wnd, Class, nIndex);
1024 }
1025 else
1026 {
1027 WARN("Invalid class for hwnd 0x%p!\n", hWnd);
1028 }
1029 }
1030 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1031 {
1032 Ret = 0;
1033 }
1034 _SEH2_END;
1035
1036 return Ret;
1037 }
1038 #endif
1039
1040
1041 /*
1042 * @implemented
1043 */
1044 int WINAPI
1045 GetClassNameA(
1046 HWND hWnd,
1047 LPSTR lpClassName,
1048 int nMaxCount)
1049 {
1050 WCHAR tmpbuf[MAX_ATOM_LEN + 1];
1051 int len;
1052
1053 if (nMaxCount <= 0) return 0;
1054 if (!GetClassNameW( hWnd, tmpbuf, sizeof(tmpbuf)/sizeof(WCHAR) )) return 0;
1055 RtlUnicodeToMultiByteN( lpClassName, nMaxCount - 1, (PULONG)&len, tmpbuf, strlenW(tmpbuf) * sizeof(WCHAR) );
1056 lpClassName[len] = 0;
1057
1058 TRACE("%p class/atom: %s/%04x %x\n", hWnd,
1059 IS_ATOM(lpClassName) ? NULL : lpClassName,
1060 IS_ATOM(lpClassName) ? lpClassName : 0,
1061 nMaxCount);
1062
1063 return len;
1064 }
1065
1066
1067 /*
1068 * @implemented
1069 */
1070 int
1071 WINAPI
1072 GetClassNameW(
1073 HWND hWnd,
1074 LPWSTR lpClassName,
1075 int nMaxCount)
1076 {
1077 UNICODE_STRING ClassName;
1078 int Result;
1079
1080 ClassName.MaximumLength = nMaxCount * sizeof(WCHAR);
1081 ClassName.Buffer = lpClassName;
1082
1083 Result = NtUserGetClassName(hWnd,
1084 FALSE,
1085 &ClassName);
1086
1087 TRACE("%p class/atom: %S/%04x %x\n", hWnd,
1088 IS_ATOM(lpClassName) ? NULL : lpClassName,
1089 IS_ATOM(lpClassName) ? lpClassName : 0,
1090 nMaxCount);
1091
1092 return Result;
1093 }
1094
1095
1096 /*
1097 * @implemented
1098 */
1099 WORD
1100 WINAPI
1101 GetClassWord(
1102 HWND hwnd,
1103 int offset)
1104 {
1105 PWND Wnd;
1106 PCLS class;
1107 WORD retvalue = 0;
1108
1109 if (offset < 0) return GetClassLongA( hwnd, offset );
1110
1111 Wnd = ValidateHwnd(hwnd);
1112 if (!Wnd)
1113 return 0;
1114
1115 class = DesktopPtrToUser(Wnd->pcls);
1116 if (class == NULL) return 0;
1117
1118 if (offset <= class->cbclsExtra - sizeof(WORD))
1119 memcpy( &retvalue, (char *)(class + 1) + offset, sizeof(retvalue) );
1120 else
1121 SetLastError( ERROR_INVALID_INDEX );
1122
1123 return retvalue;
1124 }
1125
1126
1127 LONG_PTR IntGetWindowLong( HWND hwnd, INT offset, UINT size, BOOL unicode )
1128 {
1129 LONG_PTR retvalue = 0;
1130 WND *wndPtr;
1131
1132 if (offset == GWLP_HWNDPARENT)
1133 {
1134 HWND parent = GetAncestor( hwnd, GA_PARENT );
1135 if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
1136 return (ULONG_PTR)parent;
1137 }
1138
1139 if (!(wndPtr = ValidateHwnd( hwnd )))
1140 {
1141 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1142 return 0;
1143 }
1144
1145 if (offset >= 0)
1146 {
1147 if (offset > (int)(wndPtr->cbwndExtra - size))
1148 {
1149 WARN("Invalid offset %d\n", offset );
1150 SetLastError( ERROR_INVALID_INDEX );
1151 return 0;
1152 }
1153 retvalue = *((LONG_PTR *)((PCHAR)(wndPtr + 1) + offset));
1154
1155 /* WINE: special case for dialog window procedure */
1156 //if ((offset == DWLP_DLGPROC) && (size == sizeof(LONG_PTR)) && (wndPtr->flags & WIN_ISDIALOG))
1157 // retvalue = (LONG_PTR)IntGetWndProc( (WNDPROC)retvalue, unicode );
1158 return retvalue;
1159 }
1160
1161 switch(offset)
1162 {
1163 case GWLP_USERDATA: retvalue = wndPtr->dwUserData; break;
1164 case GWL_STYLE: retvalue = wndPtr->style; break;
1165 case GWL_EXSTYLE: retvalue = wndPtr->ExStyle; break;
1166 case GWLP_ID: retvalue = wndPtr->IDMenu; break;
1167 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wndPtr->hModule; break;
1168 case GWLP_WNDPROC:
1169 {
1170 if (!TestWindowProcess(wndPtr))
1171 {
1172 SetLastError(ERROR_ACCESS_DENIED);
1173 retvalue = 0;
1174 }
1175 retvalue = (ULONG_PTR)IntGetWndProc(wndPtr, !unicode);
1176 break;
1177 }
1178 default:
1179 WARN("Unknown offset %d\n", offset );
1180 SetLastError( ERROR_INVALID_INDEX );
1181 break;
1182 }
1183 return retvalue;
1184
1185 }
1186 /*
1187 * @implemented
1188 */
1189 LONG
1190 WINAPI
1191 GetWindowLongA ( HWND hWnd, int nIndex )
1192 {
1193 return IntGetWindowLong( hWnd, nIndex, sizeof(LONG), FALSE );
1194 }
1195
1196 /*
1197 * @implemented
1198 */
1199 LONG
1200 WINAPI
1201 GetWindowLongW(HWND hWnd, int nIndex)
1202 {
1203 return IntGetWindowLong( hWnd, nIndex, sizeof(LONG), TRUE );
1204 }
1205
1206 #ifdef _WIN64
1207 /*
1208 * @implemented
1209 */
1210 LONG_PTR
1211 WINAPI
1212 GetWindowLongPtrA(HWND hWnd,
1213 INT nIndex)
1214 {
1215 return IntGetWindowLong( hWnd, nIndex, sizeof(LONG_PTR), FALSE );
1216 }
1217
1218 /*
1219 * @implemented
1220 */
1221 LONG_PTR
1222 WINAPI
1223 GetWindowLongPtrW(HWND hWnd,
1224 INT nIndex)
1225 {
1226 return IntGetWindowLong( hWnd, nIndex, sizeof(LONG_PTR), TRUE );
1227
1228 }
1229 #endif // _WIN64
1230
1231 /*
1232 * @implemented
1233 */
1234 WORD
1235 WINAPI
1236 GetWindowWord(HWND hWnd, int nIndex)
1237 {
1238 switch(nIndex)
1239 {
1240 case GWLP_ID:
1241 case GWLP_HINSTANCE:
1242 case GWLP_HWNDPARENT:
1243 break;
1244 default:
1245 if (nIndex < 0)
1246 {
1247 WARN("Invalid offset %d\n", nIndex );
1248 SetLastError( ERROR_INVALID_INDEX );
1249 return 0;
1250 }
1251 break;
1252 }
1253 return IntGetWindowLong( hWnd, nIndex, sizeof(WORD), FALSE );
1254 }
1255
1256 /*
1257 * @implemented
1258 */
1259 UINT
1260 WINAPI
1261 RealGetWindowClassW(
1262 HWND hwnd,
1263 LPWSTR pszType,
1264 UINT cchType)
1265 {
1266 UNICODE_STRING ClassName;
1267 ClassName.MaximumLength = cchType * sizeof(WCHAR);
1268 ClassName.Buffer = (PWSTR)pszType;
1269
1270 return NtUserGetClassName(hwnd,TRUE,&ClassName);
1271 }
1272
1273
1274 /*
1275 * @implemented
1276 */
1277 UINT
1278 WINAPI
1279 RealGetWindowClassA(
1280 HWND hwnd,
1281 LPSTR pszType,
1282 UINT cchType)
1283 {
1284 WCHAR tmpbuf[MAX_ATOM_LEN + 1];
1285 UINT len;
1286
1287 if ((INT)cchType <= 0) return 0;
1288 if (!RealGetWindowClassW( hwnd, tmpbuf, sizeof(tmpbuf)/sizeof(WCHAR) )) return 0;
1289 RtlUnicodeToMultiByteN( pszType, cchType - 1, (PULONG)&len, tmpbuf, strlenW(tmpbuf) * sizeof(WCHAR) );
1290 pszType[len] = 0;
1291 return len;
1292 }
1293
1294 /*
1295 * Create a small icon based on a standard icon
1296 */
1297 #if 0 // Keep vintage code from revision 18764 by GvG!
1298 static HICON
1299 CreateSmallIcon(HICON StdIcon)
1300 {
1301 HICON SmallIcon = NULL;
1302 ICONINFO StdInfo;
1303 int SmallIconWidth;
1304 int SmallIconHeight;
1305 BITMAP StdBitmapInfo;
1306 HDC hSourceDc = NULL;
1307 HDC hDestDc = NULL;
1308 ICONINFO SmallInfo;
1309 HBITMAP OldSourceBitmap = NULL;
1310 HBITMAP OldDestBitmap = NULL;
1311
1312 SmallInfo.hbmColor = NULL;
1313 SmallInfo.hbmMask = NULL;
1314
1315 /* We need something to work with... */
1316 if (NULL == StdIcon)
1317 {
1318 goto cleanup;
1319 }
1320
1321 SmallIconWidth = GetSystemMetrics(SM_CXSMICON);
1322 SmallIconHeight = GetSystemMetrics(SM_CYSMICON);
1323 if (! GetIconInfo(StdIcon, &StdInfo))
1324 {
1325 ERR("Failed to get icon info for icon 0x%x\n", StdIcon);
1326 goto cleanup;
1327 }
1328 if (! GetObjectW(StdInfo.hbmMask, sizeof(BITMAP), &StdBitmapInfo))
1329 {
1330 ERR("Failed to get bitmap info for icon 0x%x bitmap 0x%x\n",
1331 StdIcon, StdInfo.hbmColor);
1332 goto cleanup;
1333 }
1334 if (StdBitmapInfo.bmWidth == SmallIconWidth &&
1335 StdBitmapInfo.bmHeight == SmallIconHeight)
1336 {
1337 /* Icon already has the correct dimensions */
1338 return StdIcon;
1339 }
1340
1341 hSourceDc = CreateCompatibleDC(NULL);
1342 if (NULL == hSourceDc)
1343 {
1344 ERR("Failed to create source DC\n");
1345 goto cleanup;
1346 }
1347 hDestDc = CreateCompatibleDC(NULL);
1348 if (NULL == hDestDc)
1349 {
1350 ERR("Failed to create dest DC\n");
1351 goto cleanup;
1352 }
1353
1354 OldSourceBitmap = SelectObject(hSourceDc, StdInfo.hbmColor);
1355 if (NULL == OldSourceBitmap)
1356 {
1357 ERR("Failed to select source color bitmap\n");
1358 goto cleanup;
1359 }
1360 SmallInfo.hbmColor = CreateCompatibleBitmap(hSourceDc, SmallIconWidth,
1361 SmallIconHeight);
1362 if (NULL == SmallInfo.hbmColor)
1363 {
1364 ERR("Failed to create color bitmap\n");
1365 goto cleanup;
1366 }
1367 OldDestBitmap = SelectObject(hDestDc, SmallInfo.hbmColor);
1368 if (NULL == OldDestBitmap)
1369 {
1370 ERR("Failed to select dest color bitmap\n");
1371 goto cleanup;
1372 }
1373 if (! StretchBlt(hDestDc, 0, 0, SmallIconWidth, SmallIconHeight,
1374 hSourceDc, 0, 0, StdBitmapInfo.bmWidth,
1375 StdBitmapInfo.bmHeight, SRCCOPY))
1376 {
1377 ERR("Failed to stretch color bitmap\n");
1378 goto cleanup;
1379 }
1380
1381 if (NULL == SelectObject(hSourceDc, StdInfo.hbmMask))
1382 {
1383 ERR("Failed to select source mask bitmap\n");
1384 goto cleanup;
1385 }
1386 SmallInfo.hbmMask = CreateCompatibleBitmap(hSourceDc, SmallIconWidth, SmallIconHeight);
1387 if (NULL == SmallInfo.hbmMask)
1388 {
1389 ERR("Failed to create mask bitmap\n");
1390 goto cleanup;
1391 }
1392 if (NULL == SelectObject(hDestDc, SmallInfo.hbmMask))
1393 {
1394 ERR("Failed to select dest mask bitmap\n");
1395 goto cleanup;
1396 }
1397 if (! StretchBlt(hDestDc, 0, 0, SmallIconWidth, SmallIconHeight,
1398 hSourceDc, 0, 0, StdBitmapInfo.bmWidth,
1399 StdBitmapInfo.bmHeight, SRCCOPY))
1400 {
1401 ERR("Failed to stretch mask bitmap\n");
1402 goto cleanup;
1403 }
1404
1405 SmallInfo.fIcon = TRUE;
1406 SmallInfo.xHotspot = SmallIconWidth / 2;
1407 SmallInfo.yHotspot = SmallIconHeight / 2;
1408 SmallIcon = CreateIconIndirect(&SmallInfo);
1409 if (NULL == SmallIcon)
1410 {
1411 ERR("Failed to create icon\n");
1412 goto cleanup;
1413 }
1414
1415 cleanup:
1416 if (NULL != SmallInfo.hbmMask)
1417 {
1418 DeleteObject(SmallInfo.hbmMask);
1419 }
1420 if (NULL != OldDestBitmap)
1421 {
1422 SelectObject(hDestDc, OldDestBitmap);
1423 }
1424 if (NULL != SmallInfo.hbmColor)
1425 {
1426 DeleteObject(SmallInfo.hbmColor);
1427 }
1428 if (NULL != hDestDc)
1429 {
1430 DeleteDC(hDestDc);
1431 }
1432 if (NULL != OldSourceBitmap)
1433 {
1434 SelectObject(hSourceDc, OldSourceBitmap);
1435 }
1436 if (NULL != hSourceDc)
1437 {
1438 DeleteDC(hSourceDc);
1439 }
1440
1441 return SmallIcon;
1442 }
1443 #endif
1444
1445 ATOM WINAPI
1446 RegisterClassExWOWW(WNDCLASSEXW *lpwcx,
1447 LPDWORD pdwWowData,
1448 WORD fnID,
1449 DWORD dwFlags,
1450 BOOL ChkRegCls)
1451 {
1452 ATOM Atom;
1453 WNDCLASSEXW WndClass;
1454 UNICODE_STRING ClassName;
1455 UNICODE_STRING MenuName = {0};
1456 CLSMENUNAME clsMenuName;
1457 ANSI_STRING AnsiMenuName;
1458 HMODULE hLibModule = NULL;
1459 DWORD save_error;
1460 BOOL ClassFound = FALSE;
1461
1462 if (lpwcx == NULL || lpwcx->cbSize != sizeof(WNDCLASSEXW) ||
1463 lpwcx->cbClsExtra < 0 || lpwcx->cbWndExtra < 0 ||
1464 lpwcx->lpszClassName == NULL)
1465 {
1466 TRACE("RegisterClassExWOWW Invalid Parameter Error!\n");
1467 SetLastError(ERROR_INVALID_PARAMETER);
1468 return 0;
1469 }
1470
1471 if (ChkRegCls)
1472 {
1473 if (!RegisterDefaultClasses) RegisterSystemControls();
1474 }
1475 /*
1476 * On real Windows this looks more like:
1477 * if (lpwcx->hInstance == User32Instance &&
1478 * *(PULONG)((ULONG_PTR)NtCurrentTeb() + 0x6D4) & 0x400)
1479 * But since I have no idea what the magic field in the
1480 * TEB structure means, I rather decided to omit that.
1481 * -- Filip Navara
1482
1483 GetWin32ClientInfo()->dwExpWinVer & (WINVER == 0x400)
1484 */
1485 if (lpwcx->hInstance == User32Instance)
1486 {
1487 TRACE("RegisterClassExWOWW User32Instance!\n");
1488 SetLastError(ERROR_INVALID_PARAMETER);
1489 return 0;
1490 }
1491 /* Yes, this is correct. We should modify the passed structure. */
1492 if (lpwcx->hInstance == NULL)
1493 ((WNDCLASSEXW*)lpwcx)->hInstance = GetModuleHandleW(NULL);
1494
1495 RtlCopyMemory(&WndClass, lpwcx, sizeof(WNDCLASSEXW));
1496 /*
1497 if (NULL == WndClass.hIconSm)
1498 {
1499 WndClass.hIconSm = CreateSmallIcon(WndClass.hIcon);
1500 }
1501 */
1502 RtlInitEmptyAnsiString(&AnsiMenuName, NULL, 0);
1503 if (WndClass.lpszMenuName != NULL)
1504 {
1505 if (!IS_INTRESOURCE(WndClass.lpszMenuName))
1506 {
1507 if (WndClass.lpszMenuName[0])
1508 {
1509 RtlInitUnicodeString(&MenuName, WndClass.lpszMenuName);
1510 RtlUnicodeStringToAnsiString( &AnsiMenuName, &MenuName, TRUE);
1511 }
1512 }
1513 else
1514 {
1515 MenuName.Buffer = (LPWSTR)WndClass.lpszMenuName;
1516 AnsiMenuName.Buffer = (PCHAR)WndClass.lpszMenuName;
1517 }
1518 }
1519
1520 if (IS_ATOM(WndClass.lpszClassName))
1521 {
1522 ClassName.Length =
1523 ClassName.MaximumLength = 0;
1524 ClassName.Buffer = (LPWSTR)WndClass.lpszClassName;
1525 }
1526 else
1527 {
1528 RtlInitUnicodeString(&ClassName, WndClass.lpszClassName);
1529 }
1530
1531 clsMenuName.pszClientAnsiMenuName = AnsiMenuName.Buffer;
1532 clsMenuName.pwszClientUnicodeMenuName = MenuName.Buffer;
1533 clsMenuName.pusMenuName = &MenuName;
1534
1535 for(;;)
1536 {
1537 Atom = NtUserRegisterClassExWOW( &WndClass,
1538 &ClassName,
1539 NULL, //PUNICODE_STRING ClsNVersion,
1540 &clsMenuName,
1541 fnID,
1542 dwFlags,
1543 pdwWowData);
1544
1545 if (Atom) break;
1546 if (!ClassFound)
1547 {
1548 save_error = GetLastError();
1549 if ( save_error == ERROR_CANNOT_FIND_WND_CLASS ||
1550 save_error == ERROR_CLASS_DOES_NOT_EXIST )
1551 {
1552 ClassFound = VersionRegisterClass(ClassName.Buffer, NULL, NULL, &hLibModule);
1553 if (ClassFound) continue;
1554 }
1555 }
1556 if (hLibModule)
1557 {
1558 save_error = GetLastError();
1559 FreeLibrary(hLibModule);
1560 SetLastError(save_error);
1561 hLibModule = 0;
1562 }
1563 break;
1564 }
1565
1566 TRACE("atom=%04x wndproc=%p hinst=%p bg=%p style=%08x clsExt=%d winExt=%d class=%p\n",
1567 Atom, lpwcx->lpfnWndProc, lpwcx->hInstance, lpwcx->hbrBackground,
1568 lpwcx->style, lpwcx->cbClsExtra, lpwcx->cbWndExtra, WndClass);
1569
1570 return Atom;
1571 }
1572
1573 /*
1574 * @implemented
1575 */
1576 ATOM WINAPI
1577 RegisterClassExA(CONST WNDCLASSEXA *lpwcx)
1578 {
1579 RTL_ATOM Atom;
1580 WNDCLASSEXW WndClass;
1581 WCHAR mname[MAX_BUFFER_LEN];
1582 WCHAR cname[MAX_BUFFER_LEN];
1583
1584 RtlCopyMemory(&WndClass, lpwcx, sizeof(WNDCLASSEXA));
1585
1586 if (WndClass.lpszMenuName != NULL)
1587 {
1588 if (!IS_INTRESOURCE(WndClass.lpszMenuName))
1589 {
1590 if (WndClass.lpszMenuName[0])
1591 {
1592 if (!MultiByteToWideChar( CP_ACP, 0, lpwcx->lpszMenuName, -1, mname, MAX_ATOM_LEN + 1 )) return 0;
1593
1594 WndClass.lpszMenuName = mname;
1595 }
1596 }
1597 }
1598
1599 if (!IS_ATOM(WndClass.lpszClassName))
1600 {
1601 if (!MultiByteToWideChar( CP_ACP, 0, lpwcx->lpszClassName, -1, cname, MAX_ATOM_LEN + 1 )) return 0;
1602
1603 WndClass.lpszClassName = cname;
1604 }
1605
1606 Atom = RegisterClassExWOWW( &WndClass,
1607 0,
1608 0,
1609 CSF_ANSIPROC,
1610 TRUE);
1611
1612 TRACE("A atom=%04x wndproc=%p hinst=%p bg=%p style=%08x clsExt=%d winExt=%d class=%p\n",
1613 Atom, lpwcx->lpfnWndProc, lpwcx->hInstance, lpwcx->hbrBackground,
1614 lpwcx->style, lpwcx->cbClsExtra, lpwcx->cbWndExtra, WndClass);
1615
1616 return (ATOM)Atom;
1617 }
1618
1619 /*
1620 * @implemented
1621 */
1622 ATOM WINAPI
1623 RegisterClassExW(CONST WNDCLASSEXW *lpwcx)
1624 {
1625 ATOM Atom;
1626
1627 Atom = RegisterClassExWOWW( (WNDCLASSEXW *)lpwcx, 0, 0, 0, TRUE);
1628
1629 TRACE("W atom=%04x wndproc=%p hinst=%p bg=%p style=%08x clsExt=%d winExt=%d\n",
1630 Atom, lpwcx->lpfnWndProc, lpwcx->hInstance, lpwcx->hbrBackground,
1631 lpwcx->style, lpwcx->cbClsExtra, lpwcx->cbWndExtra);
1632
1633 return Atom;
1634 }
1635
1636 /*
1637 * @implemented
1638 */
1639 ATOM WINAPI
1640 RegisterClassA(CONST WNDCLASSA *lpWndClass)
1641 {
1642 WNDCLASSEXA Class;
1643
1644 if (lpWndClass == NULL)
1645 return 0;
1646
1647 RtlCopyMemory(&Class.style, lpWndClass, sizeof(WNDCLASSA));
1648 Class.cbSize = sizeof(WNDCLASSEXA);
1649 Class.hIconSm = NULL;
1650
1651 return RegisterClassExA(&Class);
1652 }
1653
1654 /*
1655 * @implemented
1656 */
1657 ATOM WINAPI
1658 RegisterClassW(CONST WNDCLASSW *lpWndClass)
1659 {
1660 WNDCLASSEXW Class;
1661
1662 if (lpWndClass == NULL)
1663 return 0;
1664
1665 RtlCopyMemory(&Class.style, lpWndClass, sizeof(WNDCLASSW));
1666 Class.cbSize = sizeof(WNDCLASSEXW);
1667 Class.hIconSm = NULL;
1668
1669 return RegisterClassExW(&Class);
1670 }
1671
1672 /*
1673 * @implemented
1674 */
1675 DWORD
1676 WINAPI
1677 SetClassLongA (HWND hWnd,
1678 int nIndex,
1679 LONG dwNewLong)
1680 {
1681 PSTR lpStr = (PSTR)(ULONG_PTR)dwNewLong;
1682 UNICODE_STRING Value = {0};
1683 BOOL Allocated = FALSE;
1684 DWORD Ret;
1685
1686 /* FIXME - portability!!!! */
1687
1688 if (nIndex == GCL_MENUNAME && lpStr != NULL)
1689 {
1690 if (!IS_INTRESOURCE(lpStr))
1691 {
1692 if (!RtlCreateUnicodeStringFromAsciiz(&Value,
1693 lpStr))
1694 {
1695 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1696 return 0;
1697 }
1698
1699 Allocated = TRUE;
1700 }
1701 else
1702 Value.Buffer = (PWSTR)lpStr;
1703
1704 dwNewLong = (LONG_PTR)&Value;
1705 }
1706 else if (nIndex == GCW_ATOM && lpStr != NULL)
1707 {
1708 if (!IS_ATOM(lpStr))
1709 {
1710 if (!RtlCreateUnicodeStringFromAsciiz(&Value,
1711 lpStr))
1712 {
1713 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1714 return 0;
1715 }
1716
1717 Allocated = TRUE;
1718 }
1719 else
1720 Value.Buffer = (PWSTR)lpStr;
1721
1722 dwNewLong = (LONG_PTR)&Value;
1723 }
1724
1725 Ret = (DWORD)NtUserSetClassLong(hWnd,
1726 nIndex,
1727 dwNewLong,
1728 TRUE);
1729
1730 if (Allocated)
1731 {
1732 RtlFreeUnicodeString(&Value);
1733 }
1734
1735 return Ret;
1736 }
1737
1738
1739 /*
1740 * @implemented
1741 */
1742 DWORD
1743 WINAPI
1744 SetClassLongW(HWND hWnd,
1745 int nIndex,
1746 LONG dwNewLong)
1747 {
1748 PWSTR lpStr = (PWSTR)(ULONG_PTR)dwNewLong;
1749 UNICODE_STRING Value = {0};
1750
1751 TRACE("%p %d %lx\n", hWnd, nIndex, dwNewLong);
1752
1753 /* FIXME - portability!!!! */
1754
1755 if (nIndex == GCL_MENUNAME && lpStr != NULL)
1756 {
1757 if (!IS_INTRESOURCE(lpStr))
1758 {
1759 RtlInitUnicodeString(&Value,
1760 lpStr);
1761 }
1762 else
1763 Value.Buffer = lpStr;
1764
1765 dwNewLong = (LONG_PTR)&Value;
1766 }
1767 else if (nIndex == GCW_ATOM && lpStr != NULL)
1768 {
1769 if (!IS_ATOM(lpStr))
1770 {
1771 RtlInitUnicodeString(&Value,
1772 lpStr);
1773 }
1774 else
1775 Value.Buffer = lpStr;
1776
1777 dwNewLong = (LONG_PTR)&Value;
1778 }
1779
1780 return (DWORD)NtUserSetClassLong(hWnd,
1781 nIndex,
1782 dwNewLong,
1783 FALSE);
1784 }
1785
1786 #ifdef _WIN64
1787 /*
1788 * @unimplemented
1789 */
1790 ULONG_PTR
1791 WINAPI
1792 SetClassLongPtrA(HWND hWnd,
1793 INT nIndex,
1794 LONG_PTR dwNewLong)
1795 {
1796 UNIMPLEMENTED;
1797 return 0;
1798 }
1799
1800 /*
1801 * @unimplemented
1802 */
1803 ULONG_PTR
1804 WINAPI
1805 SetClassLongPtrW(HWND hWnd,
1806 INT nIndex,
1807 LONG_PTR dwNewLong)
1808 {
1809 UNIMPLEMENTED;
1810 return 0;
1811 }
1812 #endif // _WIN64
1813
1814 /*
1815 * @implemented
1816 */
1817 WORD
1818 WINAPI
1819 SetClassWord(
1820 HWND hWnd,
1821 int nIndex,
1822 WORD wNewWord)
1823 /*
1824 * NOTE: Obsoleted in 32-bit windows
1825 */
1826 {
1827 if ((nIndex < 0) && (nIndex != GCW_ATOM))
1828 return 0;
1829
1830 return (WORD) SetClassLongW ( hWnd, nIndex, wNewWord );
1831 }
1832
1833 /*
1834 * @implemented
1835 */
1836 WORD
1837 WINAPI
1838 SetWindowWord ( HWND hWnd,int nIndex,WORD wNewWord )
1839 {
1840 switch(nIndex)
1841 {
1842 case GWLP_ID:
1843 case GWLP_HINSTANCE:
1844 case GWLP_HWNDPARENT:
1845 break;
1846 default:
1847 if (nIndex < 0)
1848 {
1849 WARN("Invalid offset %d\n", nIndex );
1850 SetLastError( ERROR_INVALID_INDEX );
1851 return 0;
1852 }
1853 break;
1854 }
1855 return NtUserSetWindowLong( hWnd, nIndex, wNewWord, FALSE );
1856 }
1857
1858 /*
1859 * @implemented
1860 */
1861 LONG
1862 WINAPI
1863 DECLSPEC_HOTPATCH
1864 SetWindowLongA(
1865 HWND hWnd,
1866 int nIndex,
1867 LONG dwNewLong)
1868 {
1869 return NtUserSetWindowLong(hWnd, nIndex, dwNewLong, TRUE);
1870 }
1871
1872 /*
1873 * @implemented
1874 */
1875 LONG
1876 WINAPI
1877 SetWindowLongW(
1878 HWND hWnd,
1879 int nIndex,
1880 LONG dwNewLong)
1881 {
1882 return NtUserSetWindowLong(hWnd, nIndex, dwNewLong, FALSE);
1883 }
1884
1885 #ifdef _WIN64
1886 /*
1887 * @implemented
1888 */
1889 LONG_PTR
1890 WINAPI
1891 SetWindowLongPtrA(HWND hWnd,
1892 INT nIndex,
1893 LONG_PTR dwNewLong)
1894 {
1895 return NtUserSetWindowLong(hWnd, nIndex, dwNewLong, FALSE);
1896 }
1897
1898 /*
1899 * @implemented
1900 */
1901 LONG_PTR
1902 WINAPI
1903 SetWindowLongPtrW(HWND hWnd,
1904 INT nIndex,
1905 LONG_PTR dwNewLong)
1906 {
1907 return NtUserSetWindowLong(hWnd, nIndex, dwNewLong, FALSE);
1908 }
1909 #endif
1910
1911 /*
1912 * @implemented
1913 */
1914 BOOL
1915 WINAPI
1916 UnregisterClassA(
1917 LPCSTR lpClassName,
1918 HINSTANCE hInstance)
1919 {
1920 UNICODE_STRING ClassName = {0};
1921 BOOL Ret;
1922
1923 TRACE("class/atom: %s/%04x %p\n",
1924 IS_ATOM(lpClassName) ? NULL : lpClassName,
1925 IS_ATOM(lpClassName) ? lpClassName : 0,
1926 hInstance);
1927
1928 if (!IS_ATOM(lpClassName))
1929 {
1930 if (!RtlCreateUnicodeStringFromAsciiz(&ClassName,
1931 lpClassName))
1932 {
1933 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1934 return 0;
1935 }
1936 }
1937 else
1938 ClassName.Buffer = (PWSTR)((ULONG_PTR)lpClassName);
1939
1940 Ret = NtUserUnregisterClass(&ClassName,
1941 hInstance,
1942 0);
1943
1944 if (!IS_ATOM(lpClassName))
1945 RtlFreeUnicodeString(&ClassName);
1946
1947 return Ret;
1948 }
1949
1950
1951 /*
1952 * @implemented
1953 */
1954 BOOL
1955 WINAPI
1956 UnregisterClassW(
1957 LPCWSTR lpClassName,
1958 HINSTANCE hInstance)
1959 {
1960 UNICODE_STRING ClassName = {0};
1961
1962 TRACE("class/atom: %S/%04x %p\n",
1963 IS_ATOM(lpClassName) ? NULL : lpClassName,
1964 IS_ATOM(lpClassName) ? lpClassName : 0,
1965 hInstance);
1966
1967 if (!IS_ATOM(lpClassName))
1968 {
1969 RtlInitUnicodeString(&ClassName,
1970 lpClassName);
1971 }
1972 else
1973 ClassName.Buffer = (PWSTR)((ULONG_PTR)lpClassName);
1974
1975 return NtUserUnregisterClass(&ClassName,
1976 hInstance,
1977 0);
1978 }
1979
1980 /* EOF */