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

Last change on this file since 6612 was 6612, checked in by phaller, 24 years ago

fix UnregisterClass

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