xref: /reactos/win32ss/user/ntuser/callproc.c (revision c2c66aff)
1 /*
2  * COPYRIGHT:        See COPYING in the top level directory
3  * PROJECT:          ReactOS kernel
4  * PURPOSE:          Callproc support
5  * FILE:             win32ss/user/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
GetCallProcHandle(IN PCALLPROCDATA CallProc)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
DestroyCallProc(_Inout_ PVOID Object)22 DestroyCallProc(_Inout_ PVOID Object)
23 {
24     UserDeleteObject(UserHMGetHandle((PCALLPROCDATA)Object), TYPE_CALLPROC);
25     return TRUE;
26 }
27 
28 PCALLPROCDATA
CreateCallProc(IN PDESKTOP Desktop,IN WNDPROC WndProc,IN BOOL Unicode,IN PPROCESSINFO pi)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         /* Release the extra reference (UserCreateObject added 2 references) */
52         UserDereferenceObject(NewCallProc);
53     }
54 
55     return NewCallProc;
56 }
57 
58 BOOL
UserGetCallProcInfo(IN HANDLE hCallProc,OUT PWNDPROC_INFO wpInfo)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
UserSearchForCallProc(PCALLPROCDATA pcpd,WNDPROC WndProc,GETCPD Type)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
UserGetCPD(PVOID pvClsWnd,GETCPD Flags,ULONG_PTR ProcIn)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
NtUserGetCPD(HWND hWnd,GETCPD Flags,ULONG_PTR ProcIn)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 
199