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