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