[WIN32K]
[reactos.git] / reactos / win32ss / user / ntuser / callproc.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Callproc support
5 * FILE: subsystems/win32/win32k/ntuser/callproc.c
6 * PROGRAMER: Thomas Weidenmueller <w3seek@reactos.com>
7 */
8
9 #include <win32k.h>
10 DBG_DEFAULT_CHANNEL(UserClass);
11
12 /* CALLPROC ******************************************************************/
13
14 WNDPROC
15 GetCallProcHandle(IN PCALLPROCDATA CallProc)
16 {
17 /* FIXME: Check for 64 bit architectures... */
18 return (WNDPROC)((ULONG_PTR)UserHMGetHandle(CallProc) | 0xFFFF0000);
19 }
20
21 BOOLEAN
22 DestroyCallProc(_Inout_ PVOID Object)
23 {
24 UserDeleteObject(UserHMGetHandle((PCALLPROCDATA)Object), TYPE_CALLPROC);
25 return TRUE;
26 }
27
28 PCALLPROCDATA
29 CreateCallProc(IN PDESKTOP Desktop,
30 IN WNDPROC WndProc,
31 IN BOOL Unicode,
32 IN PPROCESSINFO pi)
33 {
34 PCALLPROCDATA NewCallProc;
35 HANDLE Handle;
36
37 /* We can send any thread pointer to the object manager here,
38 * What's important is the process info */
39 NewCallProc = (PCALLPROCDATA)UserCreateObject(gHandleTable,
40 Desktop,
41 pi->ptiList,
42 &Handle,
43 TYPE_CALLPROC,
44 sizeof(CALLPROCDATA));
45 if (NewCallProc != NULL)
46 {
47 NewCallProc->pfnClientPrevious = WndProc;
48 NewCallProc->wType |= Unicode ? UserGetCPDA2U : UserGetCPDU2A ;
49 NewCallProc->spcpdNext = NULL;
50 }
51
52 /* Release the extra reference (UserCreateObject added 2 references) */
53 UserDereferenceObject(NewCallProc);
54
55 return NewCallProc;
56 }
57
58 BOOL
59 UserGetCallProcInfo(IN HANDLE hCallProc,
60 OUT PWNDPROC_INFO wpInfo)
61 {
62 PCALLPROCDATA CallProc;
63
64 CallProc = UserGetObject(gHandleTable,
65 hCallProc,
66 TYPE_CALLPROC);
67 if (CallProc == NULL)
68 {
69 return FALSE;
70 }
71
72 /* Use Handle pEntry->ppi!
73 if (CallProc->pi != GetW32ProcessInfo())
74 {
75 return FALSE;
76 }*/
77
78 wpInfo->WindowProc = CallProc->pfnClientPrevious;
79 wpInfo->IsUnicode = !!(CallProc->wType & UserGetCPDA2U);
80
81 return TRUE;
82 }
83
84 /*
85 Based on UserFindCallProc.
86 */
87 PCALLPROCDATA
88 FASTCALL
89 UserSearchForCallProc(
90 PCALLPROCDATA pcpd,
91 WNDPROC WndProc,
92 GETCPD Type)
93 {
94 while ( pcpd && (pcpd->pfnClientPrevious != WndProc || pcpd->wType != Type) )
95 {
96 pcpd = pcpd->spcpdNext;
97 }
98 return pcpd;
99 }
100
101 /*
102 Get Call Proc Data handle for the window proc being requested or create a
103 new Call Proc Data handle to be return for the requested window proc.
104 */
105 ULONG_PTR
106 FASTCALL
107 UserGetCPD(
108 PVOID pvClsWnd,
109 GETCPD Flags,
110 ULONG_PTR ProcIn)
111 {
112 PCLS pCls;
113 PWND pWnd;
114 PDESKTOP pDesk;
115 PCALLPROCDATA CallProc = NULL;
116 PTHREADINFO pti;
117
118 pti = PsGetCurrentThreadWin32Thread();
119
120 if ( Flags & (UserGetCPDWindow|UserGetCPDDialog) ||
121 Flags & UserGetCPDWndtoCls)
122 {
123 pWnd = pvClsWnd;
124 pCls = pWnd->pcls;
125 }
126 else
127 pCls = pvClsWnd;
128
129 // Search Class call proc data list.
130 if (pCls->spcpdFirst)
131 CallProc = UserSearchForCallProc( pCls->spcpdFirst, (WNDPROC)ProcIn, Flags);
132
133 // No luck, create a new one for the requested proc.
134 if (!CallProc)
135 {
136 if (!pCls->rpdeskParent)
137 {
138 TRACE("Null DESKTOP Atom %u\n",pCls->atomClassName);
139 pDesk = pti->rpdesk;
140 }
141 else
142 pDesk = pCls->rpdeskParent;
143 CallProc = CreateCallProc( pDesk,
144 (WNDPROC)ProcIn,
145 !!(Flags & UserGetCPDA2U),
146 pti->ppi);
147 if (CallProc)
148 {
149 CallProc->spcpdNext = pCls->spcpdFirst;
150 (void)InterlockedExchangePointer((PVOID*)&pCls->spcpdFirst,
151 CallProc);
152 CallProc->wType = Flags;
153 }
154 }
155 return (ULONG_PTR)(CallProc ? GetCallProcHandle(CallProc) : NULL);
156 }
157
158 /* SYSCALLS *****************************************************************/
159
160 /*
161 Retrieve the WinProcA/W or CallProcData handle for Class, Dialog or Window.
162 This Function called from user space uses Window handle for class, window
163 and dialog procs only.
164
165 Note:
166 ProcIn is the default proc from pCls/pDlg/pWnd->lpfnXxyz, caller is
167 looking for another type of proc if the original lpfnXxyz proc is preset
168 to Ansi or Unicode.
169
170 Example:
171 If pWnd is created from Ansi and lpfnXxyz is assumed to be Ansi, caller
172 will ask for Unicode Proc return Proc or CallProcData handle.
173 */
174 ULONG_PTR
175 APIENTRY
176 NtUserGetCPD(
177 HWND hWnd,
178 GETCPD Flags,
179 ULONG_PTR ProcIn)
180 {
181 PWND Wnd;
182 ULONG_PTR Result = 0;
183
184 UserEnterExclusive();
185 if (!(Wnd = UserGetWindowObject(hWnd)))
186 {
187 goto Cleanup;
188 }
189
190 // Processing Window only from User space.
191 if ((Flags & ~(UserGetCPDU2A|UserGetCPDA2U)) != UserGetCPDClass)
192 Result = UserGetCPD(Wnd, Flags, ProcIn);
193
194 Cleanup:
195 UserLeave();
196 return Result;
197 }
198