Sync with trunk r63343.
[reactos.git] / base / services / rpcss / irotp.c
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 }