Fixed locking of class list.

Print ERR when accessing classes of other processes.
This commit is contained in:
Alexandre Julliard 2001-10-09 23:27:17 +00:00
parent 844ceb98ba
commit e6d90ea98f
1 changed files with 260 additions and 268 deletions

View File

@ -23,6 +23,7 @@
#include "wine/port.h" #include "wine/port.h"
#include "heap.h" #include "heap.h"
#include "win.h" #include "win.h"
#include "user.h"
#include "controls.h" #include "controls.h"
#include "dce.h" #include "dce.h"
#include "winproc.h" #include "winproc.h"
@ -52,6 +53,39 @@ typedef struct tagCLASS
static CLASS *firstClass; static CLASS *firstClass;
/***********************************************************************
* get_class_ptr
*/
static CLASS *get_class_ptr( HWND hwnd )
{
CLASS *ret = NULL;
WND *ptr = WIN_GetWndPtr( hwnd );
if (!ptr)
{
if (IsWindow( hwnd )) /* check other processes */
{
ERR( "class of window %04x belongs to other process\n", hwnd );
/* DbgBreakPoint(); */
}
}
else
{
if (ptr != BAD_WND_PTR) ret = ptr->class;
else SetLastError( ERROR_INVALID_WINDOW_HANDLE );
}
return ret;
}
/***********************************************************************
* release_class_ptr
*/
inline static void release_class_ptr( CLASS *ptr )
{
USER_Unlock();
}
/*********************************************************************** /***********************************************************************
* CLASS_GetProc * CLASS_GetProc
@ -221,11 +255,13 @@ void CLASS_FreeModuleClasses( HMODULE16 hModule )
TRACE("0x%08x\n", hModule); TRACE("0x%08x\n", hModule);
USER_Lock();
for (ptr = firstClass; ptr; ptr = next) for (ptr = firstClass; ptr; ptr = next)
{ {
next = ptr->next; next = ptr->next;
if (ptr->hInstance == hModule) CLASS_FreeClass( ptr ); if (ptr->hInstance == hModule) CLASS_FreeClass( ptr );
} }
USER_Unlock();
} }
@ -340,6 +376,30 @@ static CLASS *CLASS_RegisterClass( ATOM atom, HINSTANCE hInstance,
} }
/***********************************************************************
* CLASS_UnregisterClass
*
* The real UnregisterClass() functionality.
*/
static BOOL CLASS_UnregisterClass( ATOM atom, HINSTANCE hInstance )
{
CLASS *classPtr;
BOOL ret = FALSE;
USER_Lock();
if (atom &&
(classPtr = CLASS_FindClassByAtom( atom, hInstance )) &&
(classPtr->hInstance == hInstance))
{
ret = CLASS_FreeClass( classPtr );
}
else SetLastError( ERROR_CLASS_DOES_NOT_EXIST );
USER_Unlock();
return ret;
}
/*********************************************************************** /***********************************************************************
* CLASS_RegisterBuiltinClass * CLASS_RegisterBuiltinClass
* *
@ -647,30 +707,14 @@ BOOL16 WINAPI UnregisterClass16( LPCSTR className, HINSTANCE16 hInstance )
return UnregisterClassA( className, GetExePtr( hInstance ) ); return UnregisterClassA( className, GetExePtr( hInstance ) );
} }
/*********************************************************************** /***********************************************************************
* UnregisterClassA (USER32.@) * UnregisterClassA (USER32.@)
* *
*/ */
BOOL WINAPI UnregisterClassA( LPCSTR className, HINSTANCE hInstance ) BOOL WINAPI UnregisterClassA( LPCSTR className, HINSTANCE hInstance )
{ {
CLASS *classPtr;
ATOM atom;
TRACE("%s %x\n",debugres_a(className), hInstance); TRACE("%s %x\n",debugres_a(className), hInstance);
return CLASS_UnregisterClass( GlobalFindAtomA( className ), hInstance );
if (!(atom = GlobalFindAtomA( className )))
{
SetLastError(ERROR_CLASS_DOES_NOT_EXIST);
return FALSE;
}
if (!(classPtr = CLASS_FindClassByAtom( atom, hInstance )) ||
(classPtr->hInstance != hInstance))
{
SetLastError(ERROR_CLASS_DOES_NOT_EXIST);
return FALSE;
}
return CLASS_FreeClass( classPtr );
} }
/*********************************************************************** /***********************************************************************
@ -678,23 +722,8 @@ BOOL WINAPI UnregisterClassA( LPCSTR className, HINSTANCE hInstance )
*/ */
BOOL WINAPI UnregisterClassW( LPCWSTR className, HINSTANCE hInstance ) BOOL WINAPI UnregisterClassW( LPCWSTR className, HINSTANCE hInstance )
{ {
CLASS *classPtr;
ATOM atom;
TRACE("%s %x\n",debugres_w(className), hInstance); TRACE("%s %x\n",debugres_w(className), hInstance);
return CLASS_UnregisterClass( GlobalFindAtomW( className ), hInstance );
if (!(atom = GlobalFindAtomW( className )))
{
SetLastError(ERROR_CLASS_DOES_NOT_EXIST);
return FALSE;
}
if (!(classPtr = CLASS_FindClassByAtom( atom, hInstance )) ||
(classPtr->hInstance != hInstance))
{
SetLastError(ERROR_CLASS_DOES_NOT_EXIST);
return FALSE;
}
return CLASS_FreeClass( classPtr );
} }
@ -703,40 +732,20 @@ BOOL WINAPI UnregisterClassW( LPCWSTR className, HINSTANCE hInstance )
*/ */
WORD WINAPI GetClassWord( HWND hwnd, INT offset ) WORD WINAPI GetClassWord( HWND hwnd, INT offset )
{ {
WND * wndPtr; CLASS *class;
WORD retvalue = 0; WORD retvalue = 0;
if (offset < 0) return GetClassLongA( hwnd, offset );
TRACE("%x %x\n",hwnd, offset); TRACE("%x %x\n",hwnd, offset);
if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0; if (!(class = get_class_ptr( hwnd ))) return 0;
if (offset >= 0)
{
if (offset <= wndPtr->class->cbClsExtra - sizeof(WORD))
{
retvalue = GET_WORD((char *)(wndPtr->class + 1) + offset);
goto END;
}
}
else switch(offset)
{
case GCW_ATOM:
retvalue = wndPtr->class->atomName;
goto END;
case GCL_HBRBACKGROUND:
case GCL_HCURSOR:
case GCL_HICON:
case GCL_HICONSM:
case GCL_STYLE:
case GCL_CBWNDEXTRA:
case GCL_CBCLSEXTRA:
case GCL_HMODULE:
retvalue = (WORD)GetClassLongA( hwnd, offset );
goto END;
}
WARN("Invalid offset %d\n", offset); if (offset <= class->cbClsExtra - sizeof(WORD))
END: retvalue = GET_WORD((char *)(class + 1) + offset);
WIN_ReleaseWndPtr(wndPtr); else
SetLastError( ERROR_INVALID_INDEX );
release_class_ptr( class );
return retvalue; return retvalue;
} }
@ -744,25 +753,26 @@ WORD WINAPI GetClassWord( HWND hwnd, INT offset )
/*********************************************************************** /***********************************************************************
* GetClassLong (USER.131) * GetClassLong (USER.131)
*/ */
LONG WINAPI GetClassLong16( HWND16 hwnd, INT16 offset ) LONG WINAPI GetClassLong16( HWND16 hwnd16, INT16 offset )
{ {
WND *wndPtr; CLASS *class;
LONG ret; LONG ret;
HWND hwnd = (HWND)(ULONG_PTR)hwnd16; /* no need for full handle */
TRACE("%x %x\n",hwnd, offset); TRACE("%x %d\n",hwnd, offset);
switch( offset ) switch( offset )
{ {
case GCL_WNDPROC: case GCL_WNDPROC:
if (!(wndPtr = WIN_FindWndPtr16( hwnd ))) return 0; if (!(class = get_class_ptr( hwnd ))) return 0;
ret = (LONG)CLASS_GetProc( wndPtr->class, WIN_PROC_16 ); ret = (LONG)CLASS_GetProc( class, WIN_PROC_16 );
WIN_ReleaseWndPtr(wndPtr); release_class_ptr( class );
return ret; return ret;
case GCL_MENUNAME: case GCL_MENUNAME:
ret = GetClassLongA( WIN_Handle32(hwnd), offset ); ret = GetClassLongA( hwnd, offset );
return (LONG)SEGPTR_GET( (void *)ret ); return (LONG)SEGPTR_GET( (void *)ret );
default: default:
return GetClassLongA( WIN_Handle32(hwnd), offset ); return GetClassLongA( hwnd, offset );
} }
} }
@ -772,61 +782,63 @@ LONG WINAPI GetClassLong16( HWND16 hwnd, INT16 offset )
*/ */
LONG WINAPI GetClassLongA( HWND hwnd, INT offset ) LONG WINAPI GetClassLongA( HWND hwnd, INT offset )
{ {
WND * wndPtr; CLASS *class;
LONG retvalue; LONG retvalue = 0;
TRACE("%x %x\n",hwnd, offset); TRACE("%x %d\n", hwnd, offset);
if (!(class = get_class_ptr( hwnd ))) return 0;
if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0;
if (offset >= 0) if (offset >= 0)
{ {
if (offset <= wndPtr->class->cbClsExtra - sizeof(LONG)) if (offset <= class->cbClsExtra - sizeof(LONG))
{ retvalue = GET_DWORD((char *)(class + 1) + offset);
retvalue = GET_DWORD((char *)(wndPtr->class + 1) + offset); else
goto END; SetLastError( ERROR_INVALID_INDEX );
} release_class_ptr( class );
return retvalue;
} }
switch(offset) switch(offset)
{ {
case GCL_HBRBACKGROUND: case GCL_HBRBACKGROUND:
retvalue = (LONG)wndPtr->class->hbrBackground; retvalue = (LONG)class->hbrBackground;
goto END; break;
case GCL_HCURSOR: case GCL_HCURSOR:
retvalue = (LONG)wndPtr->class->hCursor; retvalue = (LONG)class->hCursor;
goto END; break;
case GCL_HICON: case GCL_HICON:
retvalue = (LONG)wndPtr->class->hIcon; retvalue = (LONG)class->hIcon;
goto END; break;
case GCL_HICONSM: case GCL_HICONSM:
retvalue = (LONG)wndPtr->class->hIconSm; retvalue = (LONG)class->hIconSm;
goto END; break;
case GCL_STYLE: case GCL_STYLE:
retvalue = (LONG)wndPtr->class->style; retvalue = (LONG)class->style;
goto END; break;
case GCL_CBWNDEXTRA: case GCL_CBWNDEXTRA:
retvalue = (LONG)wndPtr->class->cbWndExtra; retvalue = (LONG)class->cbWndExtra;
goto END; break;
case GCL_CBCLSEXTRA: case GCL_CBCLSEXTRA:
retvalue = (LONG)wndPtr->class->cbClsExtra; retvalue = (LONG)class->cbClsExtra;
goto END; break;
case GCL_HMODULE: case GCL_HMODULE:
retvalue = (LONG)wndPtr->class->hInstance; retvalue = (LONG)class->hInstance;
goto END; break;
case GCL_WNDPROC: case GCL_WNDPROC:
retvalue = (LONG)CLASS_GetProc( wndPtr->class, WIN_PROC_32A ); retvalue = (LONG)CLASS_GetProc( class, WIN_PROC_32A );
goto END; break;
case GCL_MENUNAME: case GCL_MENUNAME:
retvalue = (LONG)CLASS_GetMenuNameA( wndPtr->class ); retvalue = (LONG)CLASS_GetMenuNameA( class );
goto END; break;
case GCW_ATOM: case GCW_ATOM:
retvalue = GetClassWord( hwnd, offset ); retvalue = (DWORD)class->atomName;
goto END; break;
default:
SetLastError( ERROR_INVALID_INDEX );
break;
} }
WARN("Invalid offset %d\n", offset); release_class_ptr( class );
retvalue = 0;
END:
WIN_ReleaseWndPtr(wndPtr);
return retvalue; return retvalue;
} }
@ -836,26 +848,23 @@ END:
*/ */
LONG WINAPI GetClassLongW( HWND hwnd, INT offset ) LONG WINAPI GetClassLongW( HWND hwnd, INT offset )
{ {
WND * wndPtr; CLASS *class;
LONG retvalue; LONG retvalue;
TRACE("%x %x\n",hwnd, offset); if (offset != GCL_WNDPROC && offset != GCL_MENUNAME)
switch(offset)
{
case GCL_WNDPROC:
if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0;
retvalue = (LONG)CLASS_GetProc( wndPtr->class, WIN_PROC_32W );
WIN_ReleaseWndPtr(wndPtr);
return retvalue;
case GCL_MENUNAME:
if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0;
retvalue = (LONG)CLASS_GetMenuNameW( wndPtr->class );
WIN_ReleaseWndPtr(wndPtr);
return retvalue;
default:
return GetClassLongA( hwnd, offset ); return GetClassLongA( hwnd, offset );
}
TRACE("%x %d\n", hwnd, offset);
if (!(class = get_class_ptr( hwnd ))) return 0;
if (offset == GCL_WNDPROC)
retvalue = (LONG)CLASS_GetProc( class, WIN_PROC_32W );
else /* GCL_MENUNAME */
retvalue = (LONG)CLASS_GetMenuNameW( class );
release_class_ptr( class );
return retvalue;
} }
@ -864,47 +873,24 @@ LONG WINAPI GetClassLongW( HWND hwnd, INT offset )
*/ */
WORD WINAPI SetClassWord( HWND hwnd, INT offset, WORD newval ) WORD WINAPI SetClassWord( HWND hwnd, INT offset, WORD newval )
{ {
WND * wndPtr; CLASS *class;
WORD retval = 0; WORD retval = 0;
void *ptr;
TRACE("%x %x %x\n",hwnd, offset, newval); if (offset < 0) return SetClassLongA( hwnd, offset, (DWORD)newval );
if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0; TRACE("%x %d %x\n", hwnd, offset, newval);
if (offset >= 0)
if (!(class = get_class_ptr( hwnd ))) return 0;
if (offset <= class->cbClsExtra - sizeof(WORD))
{ {
if (offset + sizeof(WORD) <= wndPtr->class->cbClsExtra) void *ptr = (char *)(class + 1) + offset;
ptr = (char *)(wndPtr->class + 1) + offset; retval = GET_WORD(ptr);
else PUT_WORD( ptr, newval );
{
WARN("Invalid offset %d\n", offset );
WIN_ReleaseWndPtr(wndPtr);
return 0;
}
} }
else switch(offset) else SetLastError( ERROR_INVALID_INDEX );
{
case GCL_HBRBACKGROUND: release_class_ptr( class );
case GCL_HCURSOR:
case GCL_HICON:
case GCL_HICONSM:
case GCL_STYLE:
case GCL_CBWNDEXTRA:
case GCL_CBCLSEXTRA:
case GCL_HMODULE:
WIN_ReleaseWndPtr(wndPtr);
return (WORD)SetClassLongA( hwnd, offset, (LONG)newval );
case GCW_ATOM:
ptr = &wndPtr->class->atomName;
break;
default:
WARN("Invalid offset %d\n", offset);
WIN_ReleaseWndPtr(wndPtr);
return 0;
}
retval = GET_WORD(ptr);
PUT_WORD( ptr, newval );
WIN_ReleaseWndPtr(wndPtr);
return retval; return retval;
} }
@ -912,25 +898,26 @@ WORD WINAPI SetClassWord( HWND hwnd, INT offset, WORD newval )
/*********************************************************************** /***********************************************************************
* SetClassLong (USER.132) * SetClassLong (USER.132)
*/ */
LONG WINAPI SetClassLong16( HWND16 hwnd, INT16 offset, LONG newval ) LONG WINAPI SetClassLong16( HWND16 hwnd16, INT16 offset, LONG newval )
{ {
WND *wndPtr; CLASS *class;
LONG retval; LONG retval;
HWND hwnd = (HWND)(ULONG_PTR)hwnd16; /* no need for full handle */
TRACE("%x %x %lx\n",hwnd, offset, newval); TRACE("%x %d %lx\n", hwnd, offset, newval);
switch(offset) switch(offset)
{ {
case GCL_WNDPROC: case GCL_WNDPROC:
if (!(wndPtr = WIN_FindWndPtr16(hwnd))) return 0; if (!(class = get_class_ptr( hwnd ))) return 0;
retval = (LONG)CLASS_SetProc( wndPtr->class, (WNDPROC)newval, WIN_PROC_16 ); retval = (LONG)CLASS_SetProc( class, (WNDPROC)newval, WIN_PROC_16 );
WIN_ReleaseWndPtr(wndPtr); release_class_ptr( class );
return retval; return retval;
case GCL_MENUNAME: case GCL_MENUNAME:
newval = (LONG)MapSL( newval ); newval = (LONG)MapSL( newval );
/* fall through */ /* fall through */
default: default:
return SetClassLongA( WIN_Handle32(hwnd), offset, newval ); return SetClassLongA( hwnd, offset, newval );
} }
} }
@ -940,69 +927,73 @@ LONG WINAPI SetClassLong16( HWND16 hwnd, INT16 offset, LONG newval )
*/ */
LONG WINAPI SetClassLongA( HWND hwnd, INT offset, LONG newval ) LONG WINAPI SetClassLongA( HWND hwnd, INT offset, LONG newval )
{ {
WND * wndPtr; CLASS *class;
LONG retval = 0; LONG retval = 0;
void *ptr;
TRACE("%x %x %lx\n",hwnd, offset, newval); TRACE("%x %d %lx\n", hwnd, offset, newval);
if (!(class = get_class_ptr( hwnd ))) return 0;
if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0;
if (offset >= 0) if (offset >= 0)
{ {
if (offset + sizeof(LONG) <= wndPtr->class->cbClsExtra) if (offset <= class->cbClsExtra - sizeof(LONG))
ptr = (char *)(wndPtr->class + 1) + offset;
else
{ {
WARN("Invalid offset %d\n", offset ); void *ptr = (char *)(class + 1) + offset;
retval = 0; retval = GET_DWORD(ptr);
goto END; PUT_DWORD( ptr, newval );
} }
else SetLastError( ERROR_INVALID_INDEX );
} }
else switch(offset) else switch(offset)
{ {
case GCL_MENUNAME: case GCL_MENUNAME:
CLASS_SetMenuNameA( wndPtr->class, (LPCSTR)newval ); CLASS_SetMenuNameA( class, (LPCSTR)newval );
retval = 0; /* Old value is now meaningless anyway */ retval = 0; /* Old value is now meaningless anyway */
goto END; break;
case GCL_WNDPROC: case GCL_WNDPROC:
retval = (LONG)CLASS_SetProc( wndPtr->class, (WNDPROC)newval, WIN_PROC_32A ); retval = (LONG)CLASS_SetProc( class, (WNDPROC)newval, WIN_PROC_32A );
goto END; break;
case GCL_HBRBACKGROUND: case GCL_HBRBACKGROUND:
ptr = &wndPtr->class->hbrBackground; retval = (LONG)class->hbrBackground;
break; class->hbrBackground = newval;
case GCL_HCURSOR: break;
ptr = &wndPtr->class->hCursor; case GCL_HCURSOR:
break; retval = (LONG)class->hCursor;
case GCL_HICON: class->hCursor = newval;
ptr = &wndPtr->class->hIcon; break;
break; case GCL_HICON:
case GCL_HICONSM: retval = (LONG)class->hIcon;
ptr = &wndPtr->class->hIconSm; class->hIcon = newval;
break; break;
case GCL_STYLE: case GCL_HICONSM:
ptr = &wndPtr->class->style; retval = (LONG)class->hIconSm;
break; class->hIconSm = newval;
case GCL_CBWNDEXTRA: break;
ptr = &wndPtr->class->cbWndExtra; case GCL_STYLE:
break; retval = (LONG)class->style;
case GCL_CBCLSEXTRA: class->style = newval;
ptr = &wndPtr->class->cbClsExtra; break;
break; case GCL_CBWNDEXTRA:
case GCL_HMODULE: retval = (LONG)class->cbWndExtra;
ptr = &wndPtr->class->hInstance; class->cbWndExtra = newval;
break; break;
case GCW_ATOM: case GCL_CBCLSEXTRA:
WIN_ReleaseWndPtr(wndPtr); retval = (LONG)class->cbClsExtra;
return SetClassWord( hwnd, offset, newval ); class->cbClsExtra = newval;
default: break;
WARN("Invalid offset %d\n", offset ); case GCL_HMODULE:
retval = 0; retval = (LONG)class->hInstance;
goto END; class->hInstance = newval;
break;
case GCW_ATOM:
retval = (DWORD)class->atomName;
class->atomName = newval;
break;
default:
SetLastError( ERROR_INVALID_INDEX );
break;
} }
retval = GET_DWORD(ptr); release_class_ptr( class );
PUT_DWORD( ptr, newval );
END:
WIN_ReleaseWndPtr(wndPtr);
return retval; return retval;
} }
@ -1012,26 +1003,25 @@ END:
*/ */
LONG WINAPI SetClassLongW( HWND hwnd, INT offset, LONG newval ) LONG WINAPI SetClassLongW( HWND hwnd, INT offset, LONG newval )
{ {
WND *wndPtr; CLASS *class;
LONG retval; LONG retval;
TRACE("%x %x %lx\n",hwnd, offset, newval); if (offset != GCL_WNDPROC && offset != GCL_MENUNAME)
switch(offset)
{
case GCL_WNDPROC:
if (!(wndPtr = WIN_FindWndPtr(hwnd))) return 0;
retval = (LONG)CLASS_SetProc( wndPtr->class, (WNDPROC)newval, WIN_PROC_32W );
WIN_ReleaseWndPtr(wndPtr);
return retval;
case GCL_MENUNAME:
if (!(wndPtr = WIN_FindWndPtr(hwnd))) return 0;
CLASS_SetMenuNameW( wndPtr->class, (LPCWSTR)newval );
WIN_ReleaseWndPtr(wndPtr);
return 0; /* Old value is now meaningless anyway */
default:
return SetClassLongA( hwnd, offset, newval ); return SetClassLongA( hwnd, offset, newval );
TRACE("%x %d %lx\n", hwnd, offset, newval);
if (!(class = get_class_ptr( hwnd ))) return 0;
if (offset == GCL_WNDPROC)
retval = (LONG)CLASS_SetProc( class, (WNDPROC)newval, WIN_PROC_32W );
else /* GCL_MENUNAME */
{
CLASS_SetMenuNameW( class, (LPCWSTR)newval );
retval = 0; /* Old value is now meaningless anyway */
} }
release_class_ptr( class );
return retval;
} }
@ -1039,14 +1029,15 @@ LONG WINAPI SetClassLongW( HWND hwnd, INT offset, LONG newval )
* GetClassNameA (USER32.@) * GetClassNameA (USER32.@)
*/ */
INT WINAPI GetClassNameA( HWND hwnd, LPSTR buffer, INT count ) INT WINAPI GetClassNameA( HWND hwnd, LPSTR buffer, INT count )
{ INT ret; {
WND *wndPtr; INT ret;
CLASS *class;
if (!(wndPtr = WIN_FindWndPtr(hwnd))) return 0; if (!(class = get_class_ptr( hwnd ))) return 0;
ret = GlobalGetAtomNameA( wndPtr->class->atomName, buffer, count ); ret = GlobalGetAtomNameA( class->atomName, buffer, count );
release_class_ptr( class );
WIN_ReleaseWndPtr(wndPtr); TRACE("%x %s %x\n",hwnd, debugstr_a(buffer), count);
TRACE("%x %s %x\n",hwnd, buffer, count);
return ret; return ret;
} }
@ -1055,14 +1046,15 @@ INT WINAPI GetClassNameA( HWND hwnd, LPSTR buffer, INT count )
* GetClassNameW (USER32.@) * GetClassNameW (USER32.@)
*/ */
INT WINAPI GetClassNameW( HWND hwnd, LPWSTR buffer, INT count ) INT WINAPI GetClassNameW( HWND hwnd, LPWSTR buffer, INT count )
{ INT ret; {
WND *wndPtr; INT ret;
CLASS *class;
if (!(class = get_class_ptr( hwnd ))) return 0;
ret = GlobalGetAtomNameW( class->atomName, buffer, count );
release_class_ptr( class );
if (!(wndPtr = WIN_FindWndPtr(hwnd))) return 0;
ret = GlobalGetAtomNameW( wndPtr->class->atomName, buffer, count );
WIN_ReleaseWndPtr(wndPtr);
TRACE("%x %s %x\n",hwnd, debugstr_w(buffer), count); TRACE("%x %s %x\n",hwnd, debugstr_w(buffer), count);
return ret; return ret;
} }