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