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