xref: /reactos/base/services/rpcss/irotp.c (revision b819608e)
1 /*
2  *	Running Object Table
3  *
4  *      Copyright 2007  Robert Shearman
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 
21 #include "rpcss.h"
22 
23 #include <wine/debug.h>
24 
25 WINE_DEFAULT_DEBUG_CHANNEL(rpcss);
26 
27 /* define the structure of the running object table elements */
28 struct rot_entry
29 {
30     struct list        entry;
31     InterfaceData *object; /* marshaled running object*/
32     InterfaceData *moniker; /* marshaled moniker that identifies this object */
33     MonikerComparisonData *moniker_data; /* moniker comparison data that identifies this object */
34     DWORD              cookie; /* cookie identifying this object */
35     FILETIME           last_modified;
36     LONG               refs;
37 };
38 
39 static struct list RunningObjectTable = LIST_INIT(RunningObjectTable);
40 
41 static CRITICAL_SECTION csRunningObjectTable;
42 static CRITICAL_SECTION_DEBUG critsect_debug =
43 {
44     0, 0, &csRunningObjectTable,
45     { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
46       0, 0, { (DWORD_PTR)(__FILE__ ": csRunningObjectTable") }
47 };
48 static CRITICAL_SECTION csRunningObjectTable = { &critsect_debug, -1, 0, 0, 0, 0 };
49 
50 static LONG last_cookie = 1;
51 
52 static inline void rot_entry_release(struct rot_entry *rot_entry)
53 {
54     if (!InterlockedDecrement(&rot_entry->refs))
55     {
56         HeapFree(GetProcessHeap(), 0, rot_entry->object);
57         HeapFree(GetProcessHeap(), 0, rot_entry->moniker);
58         HeapFree(GetProcessHeap(), 0, rot_entry->moniker_data);
59         HeapFree(GetProcessHeap(), 0, rot_entry);
60     }
61 }
62 
63 HRESULT __cdecl IrotRegister(
64     IrotHandle h,
65     const MonikerComparisonData *data,
66     const InterfaceData *obj,
67     const InterfaceData *mk,
68     const FILETIME *time,
69     DWORD grfFlags,
70     IrotCookie *cookie,
71     IrotContextHandle *ctxt_handle)
72 {
73     struct rot_entry *rot_entry;
74     struct rot_entry *existing_rot_entry;
75     HRESULT hr;
76 
77     if (grfFlags & ~(ROTFLAGS_REGISTRATIONKEEPSALIVE|ROTFLAGS_ALLOWANYCLIENT))
78     {
79         WINE_ERR("Invalid grfFlags: 0x%08x\n", grfFlags & ~(ROTFLAGS_REGISTRATIONKEEPSALIVE|ROTFLAGS_ALLOWANYCLIENT));
80         return E_INVALIDARG;
81     }
82 
83     rot_entry = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*rot_entry));
84     if (!rot_entry)
85         return E_OUTOFMEMORY;
86 
87     rot_entry->refs = 1;
88     rot_entry->object = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(InterfaceData, abData[obj->ulCntData]));
89     if (!rot_entry->object)
90     {
91         rot_entry_release(rot_entry);
92         return E_OUTOFMEMORY;
93     }
94     rot_entry->object->ulCntData = obj->ulCntData;
95     memcpy(&rot_entry->object->abData, obj->abData, obj->ulCntData);
96 
97     rot_entry->last_modified = *time;
98 
99     rot_entry->moniker = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(InterfaceData, abData[mk->ulCntData]));
100     if (!rot_entry->moniker)
101     {
102         rot_entry_release(rot_entry);
103         return E_OUTOFMEMORY;
104     }
105     rot_entry->moniker->ulCntData = mk->ulCntData;
106     memcpy(&rot_entry->moniker->abData, mk->abData, mk->ulCntData);
107 
108     rot_entry->moniker_data = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(MonikerComparisonData, abData[data->ulCntData]));
109     if (!rot_entry->moniker_data)
110     {
111         rot_entry_release(rot_entry);
112         return E_OUTOFMEMORY;
113     }
114     rot_entry->moniker_data->ulCntData = data->ulCntData;
115     memcpy(&rot_entry->moniker_data->abData, data->abData, data->ulCntData);
116 
117     EnterCriticalSection(&csRunningObjectTable);
118 
119     hr = S_OK;
120 
121     LIST_FOR_EACH_ENTRY(existing_rot_entry, &RunningObjectTable, struct rot_entry, entry)
122     {
123         if ((existing_rot_entry->moniker_data->ulCntData == data->ulCntData) &&
124             !memcmp(&data->abData, &existing_rot_entry->moniker_data->abData, data->ulCntData))
125         {
126             hr = MK_S_MONIKERALREADYREGISTERED;
127             WINE_TRACE("moniker already registered with cookie %d\n", existing_rot_entry->cookie);
128             break;
129         }
130     }
131 
132     list_add_tail(&RunningObjectTable, &rot_entry->entry);
133 
134     LeaveCriticalSection(&csRunningObjectTable);
135 
136     /* gives a registration identifier to the registered object*/
137     *cookie = rot_entry->cookie = InterlockedIncrement(&last_cookie);
138     *ctxt_handle = rot_entry;
139 
140     return hr;
141 }
142 
143 HRESULT __cdecl IrotRevoke(
144     IrotHandle h,
145     IrotCookie cookie,
146     IrotContextHandle *ctxt_handle,
147     PInterfaceData *obj,
148     PInterfaceData *mk)
149 {
150     struct rot_entry *rot_entry;
151 
152     WINE_TRACE("%d\n", cookie);
153 
154     EnterCriticalSection(&csRunningObjectTable);
155     LIST_FOR_EACH_ENTRY(rot_entry, &RunningObjectTable, struct rot_entry, entry)
156     {
157         if (rot_entry->cookie == cookie)
158         {
159             HRESULT hr = S_OK;
160 
161             list_remove(&rot_entry->entry);
162             LeaveCriticalSection(&csRunningObjectTable);
163 
164             *obj = MIDL_user_allocate(FIELD_OFFSET(InterfaceData, abData[rot_entry->object->ulCntData]));
165             *mk = MIDL_user_allocate(FIELD_OFFSET(InterfaceData, abData[rot_entry->moniker->ulCntData]));
166             if (*obj && *mk)
167             {
168                 (*obj)->ulCntData = rot_entry->object->ulCntData;
169                 memcpy((*obj)->abData, rot_entry->object->abData, (*obj)->ulCntData);
170                 (*mk)->ulCntData = rot_entry->moniker->ulCntData;
171                 memcpy((*mk)->abData, rot_entry->moniker->abData, (*mk)->ulCntData);
172             }
173             else
174             {
175                 MIDL_user_free(*obj);
176                 MIDL_user_free(*mk);
177                 hr = E_OUTOFMEMORY;
178             }
179 
180             rot_entry_release(rot_entry);
181             *ctxt_handle = NULL;
182             return hr;
183         }
184     }
185     LeaveCriticalSection(&csRunningObjectTable);
186 
187     return E_INVALIDARG;
188 }
189 
190 HRESULT __cdecl IrotIsRunning(
191     IrotHandle h,
192     const MonikerComparisonData *data)
193 {
194     const struct rot_entry *rot_entry;
195     HRESULT hr = S_FALSE;
196 
197     WINE_TRACE("\n");
198 
199     EnterCriticalSection(&csRunningObjectTable);
200 
201     LIST_FOR_EACH_ENTRY(rot_entry, &RunningObjectTable, const struct rot_entry, entry)
202     {
203         if ((rot_entry->moniker_data->ulCntData == data->ulCntData) &&
204             !memcmp(&data->abData, &rot_entry->moniker_data->abData, data->ulCntData))
205         {
206             hr = S_OK;
207             break;
208         }
209     }
210     LeaveCriticalSection(&csRunningObjectTable);
211 
212     return hr;
213 }
214 
215 HRESULT __cdecl IrotGetObject(
216     IrotHandle h,
217     const MonikerComparisonData *moniker_data,
218     PInterfaceData *obj,
219     IrotCookie *cookie)
220 {
221     const struct rot_entry *rot_entry;
222 
223     WINE_TRACE("%p\n", moniker_data);
224 
225     *cookie = 0;
226 
227     EnterCriticalSection(&csRunningObjectTable);
228 
229     LIST_FOR_EACH_ENTRY(rot_entry, &RunningObjectTable, const struct rot_entry, entry)
230     {
231         HRESULT hr = S_OK;
232         if ((rot_entry->moniker_data->ulCntData == moniker_data->ulCntData) &&
233             !memcmp(&moniker_data->abData, &rot_entry->moniker_data->abData, moniker_data->ulCntData))
234         {
235             *obj = MIDL_user_allocate(FIELD_OFFSET(InterfaceData, abData[rot_entry->object->ulCntData]));
236             if (*obj)
237             {
238                 (*obj)->ulCntData = rot_entry->object->ulCntData;
239                 memcpy((*obj)->abData, rot_entry->object->abData, (*obj)->ulCntData);
240 
241                 *cookie = rot_entry->cookie;
242             }
243             else
244                 hr = E_OUTOFMEMORY;
245 
246             LeaveCriticalSection(&csRunningObjectTable);
247 
248             return hr;
249         }
250     }
251 
252     LeaveCriticalSection(&csRunningObjectTable);
253 
254     return MK_E_UNAVAILABLE;
255 }
256 
257 HRESULT __cdecl IrotNoteChangeTime(
258     IrotHandle h,
259     IrotCookie cookie,
260     const FILETIME *last_modified_time)
261 {
262     struct rot_entry *rot_entry;
263 
264     WINE_TRACE("%d %p\n", cookie, last_modified_time);
265 
266     EnterCriticalSection(&csRunningObjectTable);
267     LIST_FOR_EACH_ENTRY(rot_entry, &RunningObjectTable, struct rot_entry, entry)
268     {
269         if (rot_entry->cookie == cookie)
270         {
271             rot_entry->last_modified = *last_modified_time;
272             LeaveCriticalSection(&csRunningObjectTable);
273             return S_OK;
274         }
275     }
276     LeaveCriticalSection(&csRunningObjectTable);
277 
278     return E_INVALIDARG;
279 }
280 
281 HRESULT __cdecl IrotGetTimeOfLastChange(
282     IrotHandle h,
283     const MonikerComparisonData *moniker_data,
284     FILETIME *time)
285 {
286     const struct rot_entry *rot_entry;
287     HRESULT hr = MK_E_UNAVAILABLE;
288 
289     WINE_TRACE("%p\n", moniker_data);
290 
291     memset(time, 0, sizeof(*time));
292 
293     EnterCriticalSection(&csRunningObjectTable);
294     LIST_FOR_EACH_ENTRY(rot_entry, &RunningObjectTable, const struct rot_entry, entry)
295     {
296         if ((rot_entry->moniker_data->ulCntData == moniker_data->ulCntData) &&
297             !memcmp(&moniker_data->abData, &rot_entry->moniker_data->abData, moniker_data->ulCntData))
298         {
299             *time = rot_entry->last_modified;
300             hr = S_OK;
301             break;
302         }
303     }
304     LeaveCriticalSection(&csRunningObjectTable);
305 
306     return hr;
307 }
308 
309 HRESULT __cdecl IrotEnumRunning(
310     IrotHandle h,
311     PInterfaceList *list)
312 {
313     const struct rot_entry *rot_entry;
314     HRESULT hr = S_OK;
315     ULONG moniker_count = 0;
316     ULONG i = 0;
317 
318     WINE_TRACE("\n");
319 
320     EnterCriticalSection(&csRunningObjectTable);
321 
322     LIST_FOR_EACH_ENTRY( rot_entry, &RunningObjectTable, const struct rot_entry, entry )
323         moniker_count++;
324 
325     *list = MIDL_user_allocate(FIELD_OFFSET(InterfaceList, interfaces[moniker_count]));
326     if (*list)
327     {
328         (*list)->size = moniker_count;
329         LIST_FOR_EACH_ENTRY( rot_entry, &RunningObjectTable, const struct rot_entry, entry )
330         {
331             (*list)->interfaces[i] = MIDL_user_allocate(FIELD_OFFSET(InterfaceData, abData[rot_entry->moniker->ulCntData]));
332             if (!(*list)->interfaces[i])
333             {
334                 ULONG end = i - 1;
335                 for (i = 0; i < end; i++)
336                     MIDL_user_free((*list)->interfaces[i]);
337                 MIDL_user_free(*list);
338                 hr = E_OUTOFMEMORY;
339                 break;
340             }
341             (*list)->interfaces[i]->ulCntData = rot_entry->moniker->ulCntData;
342             memcpy((*list)->interfaces[i]->abData, rot_entry->moniker->abData, rot_entry->moniker->ulCntData);
343             i++;
344         }
345     }
346     else
347         hr = E_OUTOFMEMORY;
348 
349     LeaveCriticalSection(&csRunningObjectTable);
350 
351     return hr;
352 }
353 
354 void __RPC_USER IrotContextHandle_rundown(IrotContextHandle ctxt_handle)
355 {
356     struct rot_entry *rot_entry = ctxt_handle;
357     EnterCriticalSection(&csRunningObjectTable);
358     list_remove(&rot_entry->entry);
359     LeaveCriticalSection(&csRunningObjectTable);
360     rot_entry_release(rot_entry);
361 }
362 
363 void * __RPC_USER MIDL_user_allocate(SIZE_T size)
364 {
365     return HeapAlloc(GetProcessHeap(), 0, size);
366 }
367 
368 void __RPC_USER MIDL_user_free(void * p)
369 {
370     HeapFree(GetProcessHeap(), 0, p);
371 }
372