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