source: trunk/src/user32/win32class.cpp@ 5242

Last change on this file since 5242 was 5242, checked in by sandervl, 25 years ago

window & class user word access fixes

File size: 21.4 KB
Line 
1/* $Id: win32class.cpp,v 1.23 2001-02-22 10:37:30 sandervl Exp $ */
2/*
3 * Win32 Window Class Managment Code for OS/2
4 *
5 * Copyright 1998-1999 Sander van Leeuwen (sandervl@xs4all.nl)
6 *
7 *
8 * TODO: Right now all class atoms are global. This must be changed.
9 * TODO: Global atoms of classes with CS_GLOBALCLASS flag are not deleted
10 * Must all be changed if we want to support global app classes
11 * that can be used by other apps. (low priority)
12 *
13 * Project Odin Software License can be found in LICENSE.TXT
14 *
15 */
16#include <os2win.h>
17#include <stdio.h>
18#include <stdlib.h>
19#include <string.h>
20#include <stdarg.h>
21#include <assert.h>
22#include <misc.h>
23#include <win32class.h>
24#include <win32wnd.h>
25#include <win\winproc.h>
26
27#define DBG_LOCALLOG DBG_win32class
28#include "dbglocal.h"
29
30static fDestroyAll = FALSE;
31
32//******************************************************************************
33//Win32WndClass methods:
34//******************************************************************************
35Win32WndClass::Win32WndClass(WNDCLASSEXA *wndclass, BOOL fUnicode) : GenericObject(&wndclasses, OBJTYPE_CLASS)
36{
37 isUnicode = fUnicode;
38 processId = 0;
39
40 if(HIWORD(wndclass->lpszClassName)) {
41 if(isUnicode) {
42 INT len = lstrlenW((LPWSTR)wndclass->lpszClassName)+1;
43
44 classNameA = (PCHAR)_smalloc(len);
45 classNameW = (WCHAR *)_smalloc(len*sizeof(WCHAR));
46 }
47 else {
48 INT len = strlen(wndclass->lpszClassName)+1;
49
50 classNameA = (PCHAR)_smalloc(len);
51 classNameW = (WCHAR *)_smalloc(len*sizeof(WCHAR));
52 }
53 if(classNameA == NULL || classNameW == NULL) {
54 dprintf(("Win32Class ctr; classNameA/classNameW == NULL"));
55 exit(1);
56 }
57 if(isUnicode) {
58 lstrcpyW(classNameW, (LPWSTR)wndclass->lpszClassName);
59 UnicodeToAscii(classNameW, classNameA);
60 }
61 else {
62 strcpy((char *)classNameA, wndclass->lpszClassName);
63 AsciiToUnicode(classNameA, classNameW);
64 }
65 classAtom = 0;
66 //SvL: If a system control has already be registered, use that atom instead
67 // of creating a new one
68 if(wndclass->style & CS_GLOBALCLASS) {
69 classAtom = GlobalFindAtomA(classNameA);
70 }
71 if(!classAtom) classAtom = GlobalAddAtomA(classNameA);
72 }
73 else {
74 classNameA = NULL;
75 classNameW = NULL;
76 classAtom = (DWORD)wndclass->lpszClassName;
77 }
78 if(!(wndclass->style & CS_GLOBALCLASS)) {
79 processId = GetCurrentProcess();
80 }
81 menuNameA = 0;
82 menuNameW = 0;
83 setMenuName((LPSTR)wndclass->lpszMenuName);
84
85 dprintf(("USER32: Win32Class ctor\n"));
86 dprintf(("USER32: wndclass->style %X\n", wndclass->style));
87 dprintf(("USER32: wndclass->lpfnWndProc %X\n", wndclass->lpfnWndProc));
88 dprintf(("USER32: wndclass->cbClsExtra %X\n", wndclass->cbClsExtra));
89 dprintf(("USER32: wndclass->cbWndExtra %X\n", wndclass->cbWndExtra));
90 dprintf(("USER32: wndclass->hInstance %X\n", wndclass->hInstance));
91 dprintf(("USER32: wndclass->hIcon %X\n", wndclass->hIcon));
92 dprintf(("USER32: wndclass->hCursor %X\n", wndclass->hCursor));
93 dprintf(("USER32: wndclass->hbrBackground %X\n", wndclass->hbrBackground));
94 if(HIWORD(wndclass->lpszClassName))
95 dprintf(("USER32: wndclass->lpszClassName %s\n", classNameA));
96 else dprintf(("USER32: wndclass->lpszClassName %X\n", wndclass->lpszClassName));
97
98 dprintf(("USER32: wndclass->classAtom %x", classAtom));
99
100 if(HIWORD(wndclass->lpszMenuName)) {//convert string name identifier to numeric id
101 dprintf(("USER32: lpszMenuName %s\n", menuNameA));
102 }
103 else dprintf(("USER32: wndclass->lpszMenuName %X\n", menuNameA));
104 dprintf(("USER32: wndclass->hIconSm %X\n", wndclass->hIconSm));
105
106 nrExtraClassBytes = wndclass->cbClsExtra;
107 nrExtraWindowBytes = wndclass->cbWndExtra;
108 backgroundBrush = wndclass->hbrBackground;
109 hCursor = wndclass->hCursor;
110 hIcon = wndclass->hIcon;
111 hInstance = wndclass->hInstance;
112
113 if(wndclass->style & CS_CLASSDC) {
114 hdcClass = 0; //TODO:
115 }
116 else hdcClass = 0;
117
118 windowStyle = wndclass->style;
119
120 windowProc = 0;
121 WINPROC_SetProc((HWINDOWPROC *)&windowProc, wndclass->lpfnWndProc, (isUnicode) ? WIN_PROC_32W : WIN_PROC_32A, WIN_PROC_CLASS);
122 dprintf2(("Window class ptr %x", windowProc));
123
124 //User data class words/longs
125 if(nrExtraClassBytes) {
126 userClassBytes = (char *)_smalloc(nrExtraClassBytes);
127 if(userClassBytes == NULL) {
128 dprintf(("Win32Class ctr: userClassBytes == NULL!"));
129 exit(1);
130 }
131 memset(userClassBytes, 0, nrExtraClassBytes);
132 }
133 else userClassBytes = NULL;
134
135 cWindows = 0;
136 hIconSm = wndclass->hIconSm;
137}
138//******************************************************************************
139//******************************************************************************
140Win32WndClass::~Win32WndClass()
141{
142 if(classNameA) {
143 dprintf(("Win32WndClass dtor, destroy class %s\n", classNameA));
144 }
145
146 //SvL: Don't delete global classes
147 if(classNameA && !(windowStyle & CS_GLOBALCLASS)) {
148 GlobalDeleteAtom(classAtom);
149 }
150
151 WINPROC_FreeProc(windowProc, WIN_PROC_CLASS);
152
153 if(userClassBytes) free(userClassBytes);
154 if(classNameA) free(classNameA);
155 if(classNameW) free(classNameW);
156 if(menuNameA && HIWORD(menuNameA)) {
157 free(menuNameA);
158 assert(menuNameW);
159 free(menuNameW);
160 }
161}
162//******************************************************************************
163//******************************************************************************
164void Win32WndClass::DestroyAll()
165{
166 fDestroyAll = TRUE;
167 GenericObject::DestroyAll(wndclasses);
168}
169//******************************************************************************
170//******************************************************************************
171BOOL Win32WndClass::hasClassName(LPSTR classname, BOOL fUnicode)
172{
173 if(HIWORD(classname) == 0) {
174 return classAtom == (DWORD)classname;
175 }
176 if(fUnicode) {
177 if(classNameW)
178 return (lstrcmpW(classNameW, (LPWSTR)classname) == 0);
179 return FALSE;
180 }
181 else {
182 if(classNameA)
183 return (strcmp(classNameA, classname) == 0);
184 return FALSE;
185 }
186}
187//******************************************************************************
188//******************************************************************************
189Win32WndClass *Win32WndClass::FindClass(HINSTANCE hInstance, LPSTR id)
190{
191 enterMutex(OBJTYPE_CLASS);
192
193 Win32WndClass *wndclass = (Win32WndClass *)wndclasses;
194
195 if(wndclass == NULL) {
196 leaveMutex(OBJTYPE_CLASS);
197 return(NULL);
198 }
199
200 if(HIWORD(id) != 0) {
201//CB: read comment below!
202 if(lstrcmpiA(wndclass->classNameA, id) == 0 && wndclass->hInstance == hInstance) {
203 leaveMutex(OBJTYPE_CLASS);
204 return(wndclass);
205 }
206 else {
207 wndclass = (Win32WndClass *)wndclass->GetNext();
208 while(wndclass != NULL) {
209 if(lstrcmpiA(wndclass->classNameA, id) == 0)
210 {
211 //SvL: According to Wine, if the instance handle is the one of the main exe, everything is ok
212 if(hInstance == NULL || GetModuleHandleA(NULL) == hInstance ||
213 wndclass->hInstance == hInstance)
214 {
215 leaveMutex(OBJTYPE_CLASS);
216 return(wndclass);
217 }
218 }
219 wndclass = (Win32WndClass *)wndclass->GetNext();
220 }
221 }
222 }
223 else {
224//CB: without HInstance check, test program finds class
225//CB: need more code to compare instance; convert 0 to exe module handle
226 if(wndclass->classAtom == (DWORD)id /*&& wndclass->hInstance == hInstance*/) {
227 leaveMutex(OBJTYPE_CLASS);
228 return(wndclass);
229 }
230 else {
231 wndclass = (Win32WndClass *)wndclass->GetNext();
232 while(wndclass != NULL) {
233 if(wndclass->classAtom == (DWORD)id /* && wndclass->hInstance == hInstance*/) {
234 leaveMutex(OBJTYPE_CLASS);
235 return(wndclass);
236 }
237 wndclass = (Win32WndClass *)wndclass->GetNext();
238 }
239 }
240 }
241 leaveMutex(OBJTYPE_CLASS);
242 dprintf(("Class %X (inst %X) not found!", id, hInstance));
243 return(NULL);
244}
245//******************************************************************************
246//******************************************************************************
247Win32WndClass *Win32WndClass::FindClass(HINSTANCE hInstance, LPWSTR id)
248{
249 LPSTR lpszClassName;
250 Win32WndClass *winclass;
251
252 if(HIWORD(id)) {
253 lpszClassName = UnicodeToAsciiString((LPWSTR)id);
254 }
255 else lpszClassName = (LPSTR)id;
256
257 winclass = FindClass(hInstance, lpszClassName);
258
259 if(HIWORD(id)) {
260 FreeAsciiString((char *)lpszClassName);
261 }
262 return winclass;
263}
264//******************************************************************************
265//An app can only access another process' class if it's global
266//(all system classes are global)
267//NOTE: NOT USED NOW
268//******************************************************************************
269BOOL Win32WndClass::isAppClass(ULONG curProcessId)
270{
271 if(windowStyle & CS_GLOBALCLASS)
272 return TRUE;
273
274 return curProcessId = processId;
275}
276//******************************************************************************
277//******************************************************************************
278BOOL Win32WndClass::getClassInfo(WNDCLASSEXA *wndclass)
279{
280 wndclass->cbClsExtra = nrExtraClassBytes;
281 wndclass->cbWndExtra = nrExtraWindowBytes;
282 wndclass->hbrBackground = backgroundBrush;
283 wndclass->hCursor = hCursor;
284 wndclass->hIcon = hIcon;
285 wndclass->hInstance = hInstance;
286 wndclass->lpszMenuName = (LPCTSTR)menuNameA;
287 wndclass->lpszClassName = (classNameA) ? (LPCTSTR)classNameA : (LPCTSTR)classAtom;
288 wndclass->style = windowStyle;
289 wndclass->lpfnWndProc = (WNDPROC)getClassLongA(GCL_WNDPROC, FALSE);
290 wndclass->hIconSm = hIconSm;
291 return(TRUE);
292}
293//******************************************************************************
294//******************************************************************************
295BOOL Win32WndClass::getClassInfo(WNDCLASSEXW *wndclass)
296{
297 wndclass->cbClsExtra = nrExtraClassBytes;
298 wndclass->cbWndExtra = nrExtraWindowBytes;
299 wndclass->hbrBackground = backgroundBrush;
300 wndclass->hCursor = hCursor;
301 wndclass->hIcon = hIcon;
302 wndclass->hInstance = hInstance;
303 wndclass->lpszMenuName = (LPCWSTR)menuNameW;
304 wndclass->lpszClassName = (classNameW) ? (LPCWSTR)classNameW : (LPCWSTR)classAtom;
305 wndclass->style = windowStyle;
306 wndclass->lpfnWndProc = (WNDPROC)getClassLongA(GCL_WNDPROC, TRUE);
307 wndclass->hIconSm = hIconSm;
308 return(TRUE);
309}
310//******************************************************************************
311//******************************************************************************
312ULONG Win32WndClass::getClassName(LPSTR lpszClassName, ULONG cchClassName)
313{
314 if(HIWORD(classNameA)) {
315 lstrcpynA(lpszClassName, classNameA, cchClassName-1);
316 return strlen(lpszClassName);
317 }
318 *(ULONG *)lpszClassName = classAtom;
319 return(sizeof(ULONG));
320}
321//******************************************************************************
322//******************************************************************************
323ULONG Win32WndClass::getClassName(LPWSTR lpszClassName, ULONG cchClassName)
324{
325 ULONG len;
326
327 if(HIWORD(classNameW)) {
328 lstrcpyW(lpszClassName, classNameW);
329 return lstrlenW(lpszClassName)*sizeof(WCHAR);
330 }
331 *(ULONG *)lpszClassName = classAtom;
332 return(sizeof(ULONG));
333}
334//******************************************************************************
335//******************************************************************************
336void Win32WndClass::setMenuName(LPSTR newMenuName)
337{
338 if(HIWORD(menuNameA)) {
339 free(menuNameA);
340 free(menuNameW);
341 menuNameA = 0;
342 menuNameW = 0;
343 }
344 if(HIWORD(newMenuName)) {
345 if(isUnicode) {
346 menuNameA = (PCHAR)_smalloc(lstrlenW((LPWSTR)newMenuName)+1);
347 menuNameW = (WCHAR *)_smalloc((lstrlenW((LPWSTR)newMenuName)+1)*sizeof(WCHAR));
348 }
349 else {
350 menuNameA = (PCHAR)_smalloc(strlen(newMenuName)+1);
351 menuNameW = (WCHAR *)_smalloc((strlen(newMenuName)+1)*sizeof(WCHAR));
352 }
353 if(menuNameA == NULL || menuNameW == NULL) {
354 dprintf(("Win32Class ctr; menuName/menuNameW == NULL"));
355 exit(1);
356 }
357 if(isUnicode) {
358 lstrcpyW(menuNameW, (LPWSTR)newMenuName);
359 UnicodeToAscii(menuNameW, menuNameA);
360 }
361 else {
362 strcpy((char *)menuNameA, newMenuName);
363 AsciiToUnicode(menuNameA, menuNameW);
364 }
365
366 }
367 else {//id
368 menuNameA = (PCHAR)newMenuName;
369 menuNameW = (WCHAR *)newMenuName;
370 }
371}
372//******************************************************************************
373//******************************************************************************
374ULONG Win32WndClass::getClassLongA(int index, BOOL fUnicode)
375{
376 switch(index) {
377 case GCL_CBCLSEXTRA:
378 return nrExtraClassBytes;
379 case GCL_CBWNDEXTRA:
380 return nrExtraWindowBytes;
381 case GCL_HBRBACKGROUND:
382 return backgroundBrush;
383 case GCL_HCURSOR:
384 return hCursor;
385 case GCL_HICON:
386 return hIcon;
387 case GCL_HICONSM:
388 return hIconSm;
389 case GCL_HMODULE:
390 return hInstance;
391 case GCL_MENUNAME:
392 return (isUnicode) ? (ULONG)menuNameW : (ULONG)menuNameA;
393 case GCL_STYLE:
394 return windowStyle;
395 case GCL_WNDPROC:
396 return (ULONG) WINPROC_GetProc(windowProc, (fUnicode) ? WIN_PROC_32W : WIN_PROC_32A);
397 case GCW_ATOM: //TODO: does this really happen in windows?
398 SetLastError(ERROR_INVALID_PARAMETER);
399 return 0;
400 default:
401 if(index >= 0 && index + sizeof(ULONG) <= nrExtraClassBytes) {
402 //Note: NT4, SP6 does not set the last error to 0
403 SetLastError(ERROR_SUCCESS);
404 return *(ULONG *)(userClassBytes + index);
405 }
406 if(classNameA) {
407 dprintf2(("WARNING: getClassLong %s: %d -> wrong INDEX", classNameA, index));
408 }
409 else dprintf2(("WARNING: getClassLong %d: %d -> wrong INDEX", classAtom, index));
410 SetLastError(ERROR_INVALID_INDEX); //verified in NT4, SP6
411 return 0;
412 }
413}
414//******************************************************************************
415//******************************************************************************
416WORD Win32WndClass::getClassWord(int index)
417{
418 switch(index) {
419 case GCW_ATOM:
420 return (WORD)classAtom;
421 default:
422 if(index >= 0 && index + sizeof(WORD) <= nrExtraClassBytes) {
423 //Note: NT4, SP6 does not set the last error to 0
424 SetLastError(ERROR_SUCCESS);
425 return *(WORD *)(userClassBytes + index);
426 }
427 if(classNameA) {
428 dprintf2(("WARNING: getClassWord %s: %d -> wrong INDEX", classNameA, index));
429 }
430 else dprintf2(("WARNING: getClassWord %d: %d -> wrong INDEX", classAtom, index));
431 SetLastError(ERROR_INVALID_INDEX); //verified in NT4, SP6
432 return 0;
433 }
434}
435//******************************************************************************
436//TODO: What effects what immediately?
437//******************************************************************************
438ULONG Win32WndClass::setClassLongA(int index, LONG lNewVal, BOOL fUnicode)
439{
440 ULONG rc;
441
442 switch(index) {
443 case GCL_CBCLSEXTRA: //TODO (doesn't affect allocated classes, so what does it do?)
444 rc = nrExtraClassBytes;
445// nrExtraClassBytes = lNewVal;
446 break;
447 case GCL_CBWNDEXTRA:
448 rc = nrExtraWindowBytes;
449 nrExtraWindowBytes = lNewVal;
450 break;
451 case GCL_HBRBACKGROUND:
452 rc = backgroundBrush;
453 backgroundBrush = lNewVal;
454 break;
455 case GCL_HCURSOR:
456 rc = hCursor;
457 hCursor = lNewVal;
458 break;
459 case GCL_HICON:
460 rc = hIcon;
461 hIcon = lNewVal;
462 break;
463 case GCL_HICONSM:
464 rc = hIconSm;
465 hIconSm = lNewVal;
466 break;
467 case GCL_HMODULE:
468 rc = hInstance;
469 hInstance = lNewVal;
470 break;
471 case GCL_MENUNAME:
472 rc = 0; //old value is meaningless (according to Wine)
473 setMenuName((LPSTR)lNewVal);
474 break;
475 case GCL_STYLE:
476 rc = windowStyle;
477 windowStyle = lNewVal;
478 break;
479 case GCL_WNDPROC:
480 //Note: Type of SetWindowLong determines new window proc type
481 // UNLESS the new window proc has already been registered
482 // (use the old type in that case)
483 // (VERIFIED in NT 4, SP6)
484 //TODO: Is that also true for GCL_WNDPROC???????????????
485 rc = (LONG)WINPROC_GetProc(windowProc, (fUnicode) ? WIN_PROC_32W : WIN_PROC_32A );
486 WINPROC_SetProc((HWINDOWPROC *)&windowProc, (WNDPROC)lNewVal, (fUnicode) ? WIN_PROC_32W : WIN_PROC_32A, WIN_PROC_CLASS );
487 break;
488 case GCW_ATOM: //TODO: does this really happen in windows?
489 SetLastError(ERROR_INVALID_PARAMETER);
490 return 0;
491 default:
492 if(index >= 0 && index + sizeof(ULONG) <= nrExtraClassBytes) {
493 rc = *(ULONG *)(userClassBytes + index);
494 *(ULONG *)(userClassBytes + index) = lNewVal;
495 break;
496 }
497 SetLastError(ERROR_INVALID_INDEX); //verified in NT4, SP6
498 if(classNameA) {
499 dprintf2(("WARNING: Win32WndClass::setClassLongA %s: %d %x -> wrong INDEX", classNameA, index, lNewVal));
500 }
501 else dprintf2(("WARNING: Win32WndClass::setClassLongA %d: %d %x -> wrong INDEX", classAtom, index, lNewVal));
502 return 0;
503 }
504 SetLastError(ERROR_SUCCESS);
505 if(classNameA) {
506 dprintf2(("Win32WndClass::setClassLongA %s: %d %x returned %x", classNameA, index, lNewVal, rc));
507 }
508 else dprintf2(("Win32WndClass::setClassLongA %d: %d %x returned %x", classAtom, index, lNewVal, rc));
509 return(rc);
510}
511//******************************************************************************
512//******************************************************************************
513WORD Win32WndClass::setClassWord(int index, WORD wNewVal)
514{
515 WORD rc;
516
517 switch(index) {
518 case GCW_ATOM:
519 rc = (WORD)classAtom;
520 classAtom = wNewVal;
521 return(rc);
522 default:
523 if(index >= 0 && index + sizeof(WORD) <= nrExtraClassBytes) {
524 rc = *(WORD *)(userClassBytes + index);
525 *(WORD *)(userClassBytes + index) = wNewVal;
526 //Note: NT4, SP6 does not set the last error to 0
527 SetLastError(ERROR_SUCCESS);
528 return(rc);
529 }
530 SetLastError(ERROR_INVALID_INDEX); //verified in NT4, SP6
531 if(classNameA) {
532 dprintf2(("WARNING: setClassWord %s: %d %x -> wrong INDEX", classNameA, index, wNewVal));
533 }
534 else dprintf2(("WARNING: setClassWord %d: %d %x -> wrong INDEX", classAtom, index, wNewVal));
535 return 0;
536 }
537}
538//******************************************************************************
539//FIXME: Windows that still exists with this class
540//******************************************************************************
541BOOL Win32WndClass::UnregisterClassA(HINSTANCE hinst, LPSTR id)
542{
543 Win32WndClass *wndclass;
544
545 if(HIWORD(id)) {
546 dprintf(("Win32WndClass::UnregisterClassA class %s, instance %x!!", id, hinst));
547 }
548 else dprintf(("Win32WndClass::UnregisterClassA class %x, instance %x!!", id, hinst));
549
550 wndclass = FindClass(hinst, id);
551 if(wndclass) {
552 if(wndclass->GetWindowCount() != 0) {
553 dprintf2(("Win32WndClass::UnregisterClassA class %x still has windows!!", id));
554 SetLastError(ERROR_CLASS_HAS_WINDOWS);
555 return FALSE;
556 }
557 delete wndclass;
558 SetLastError(ERROR_SUCCESS);
559 return TRUE;
560 }
561 dprintf(("::UnregisterClass, couldn't find class %X!!\n", id));
562 SetLastError(ERROR_CLASS_DOES_NOT_EXIST);
563 return FALSE;
564}
565//******************************************************************************
566//******************************************************************************
567GenericObject *Win32WndClass::wndclasses = NULL;
Note: See TracBrowser for help on using the repository browser.