ole32: Add cross-process running-object table support.
[wine] / programs / 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 <stdarg.h>
22 #include <string.h>
23
24 #include "winerror.h"
25 #include "windef.h"
26 #include "winbase.h"
27
28 #include "irot.h"
29
30 #include "wine/list.h"
31 #include "wine/debug.h"
32
33 WINE_DEFAULT_DEBUG_CHANNEL(rpcss);
34
35 /* define the structure of the running object table elements */
36 struct rot_entry
37 {
38     struct list        entry;
39     InterfaceData *object; /* marshaled running object*/
40     InterfaceData *moniker; /* marshaled moniker that identifies this object */
41     MonikerComparisonData *moniker_data; /* moniker comparison data that identifies this object */
42     DWORD              cookie; /* cookie identifying this object */
43     FILETIME           last_modified;
44 };
45
46 static struct list RunningObjectTable = LIST_INIT(RunningObjectTable);
47
48 static CRITICAL_SECTION csRunningObjectTable;
49 static CRITICAL_SECTION_DEBUG critsect_debug =
50 {
51     0, 0, &csRunningObjectTable,
52     { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
53       0, 0, { (DWORD_PTR)(__FILE__ ": csRunningObjectTable") }
54 };
55 static CRITICAL_SECTION csRunningObjectTable = { &critsect_debug, -1, 0, 0, 0, 0 };
56
57 static LONG last_cookie = 1;
58
59 static inline void rot_entry_delete(struct rot_entry *rot_entry)
60 {
61     HeapFree(GetProcessHeap(), 0, rot_entry->object);
62     HeapFree(GetProcessHeap(), 0, rot_entry->moniker);
63     HeapFree(GetProcessHeap(), 0, rot_entry->moniker_data);
64     HeapFree(GetProcessHeap(), 0, rot_entry);
65 }
66
67 HRESULT IrotRegister(
68     IrotHandle h,
69     const MonikerComparisonData *data,
70     const InterfaceData *obj,
71     const InterfaceData *mk,
72     const FILETIME *time,
73     DWORD grfFlags,
74     IrotCookie *cookie)
75 {
76     struct rot_entry *rot_entry;
77     const struct rot_entry *existing_rot_entry;
78     HRESULT hr;
79
80     if (grfFlags & ~(ROTFLAGS_REGISTRATIONKEEPSALIVE|ROTFLAGS_ALLOWANYCLIENT))
81     {
82         WINE_ERR("Invalid grfFlags: 0x%08x\n", grfFlags & ~(ROTFLAGS_REGISTRATIONKEEPSALIVE|ROTFLAGS_ALLOWANYCLIENT));
83         return E_INVALIDARG;
84     }
85
86     rot_entry = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*rot_entry));
87     if (!rot_entry)
88         return E_OUTOFMEMORY;
89
90     rot_entry->object = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(InterfaceData, abData[obj->ulCntData]));
91     if (!rot_entry->object)
92     {
93         rot_entry_delete(rot_entry);
94         return E_OUTOFMEMORY;
95     }
96     rot_entry->object->ulCntData = obj->ulCntData;
97     memcpy(&rot_entry->object->abData, obj->abData, obj->ulCntData);
98
99     rot_entry->last_modified = *time;
100
101     rot_entry->moniker = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(InterfaceData, abData[mk->ulCntData]));
102     if (!rot_entry->moniker)
103     {
104         rot_entry_delete(rot_entry);
105         return E_OUTOFMEMORY;
106     }
107     rot_entry->moniker->ulCntData = mk->ulCntData;
108     memcpy(&rot_entry->moniker->abData, mk->abData, mk->ulCntData);
109
110     rot_entry->moniker_data = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(MonikerComparisonData, abData[data->ulCntData]));
111     if (!rot_entry->moniker_data)
112     {
113         rot_entry_delete(rot_entry);
114         return E_OUTOFMEMORY;
115     }
116     rot_entry->moniker_data->ulCntData = data->ulCntData;
117     memcpy(&rot_entry->moniker_data->abData, data->abData, data->ulCntData);
118
119     EnterCriticalSection(&csRunningObjectTable);
120
121     hr = S_OK;
122
123     LIST_FOR_EACH_ENTRY(existing_rot_entry, &RunningObjectTable, const struct rot_entry, entry)
124     {
125         if ((existing_rot_entry->moniker_data->ulCntData == data->ulCntData) &&
126             !memcmp(&data->abData, &existing_rot_entry->moniker_data->abData, data->ulCntData))
127         {
128             hr = MK_S_MONIKERALREADYREGISTERED;
129             WINE_TRACE("moniker already registered with cookie %d\n", existing_rot_entry->cookie);
130             break;
131         }
132     }
133
134     if (hr == S_OK)
135     {
136         list_add_tail(&RunningObjectTable, &rot_entry->entry);
137         /* gives a registration identifier to the registered object*/
138         *cookie = rot_entry->cookie = InterlockedIncrement(&last_cookie);
139     }
140     else
141     {
142         rot_entry_delete(rot_entry);
143         *cookie = existing_rot_entry->cookie;
144     }
145
146
147     LeaveCriticalSection(&csRunningObjectTable);
148
149     return hr;
150 }
151
152 HRESULT IrotRevoke(
153     IrotHandle h,
154     IrotCookie cookie,
155     PInterfaceData *obj,
156     PInterfaceData *mk)
157 {
158     struct rot_entry *rot_entry;
159
160     WINE_TRACE("%d\n", cookie);
161
162     EnterCriticalSection(&csRunningObjectTable);
163     LIST_FOR_EACH_ENTRY(rot_entry, &RunningObjectTable, struct rot_entry, entry)
164     {
165         if (rot_entry->cookie == cookie)
166         {
167             HRESULT hr = S_OK;
168
169             list_remove(&rot_entry->entry);
170             LeaveCriticalSection(&csRunningObjectTable);
171
172             *obj = MIDL_user_allocate(FIELD_OFFSET(InterfaceData, abData[rot_entry->object->ulCntData]));
173             *mk = MIDL_user_allocate(FIELD_OFFSET(InterfaceData, abData[rot_entry->moniker->ulCntData]));
174             if (*obj && *mk)
175             {
176                 (*obj)->ulCntData = rot_entry->object->ulCntData;
177                 memcpy((*obj)->abData, rot_entry->object->abData, (*obj)->ulCntData);
178                 (*mk)->ulCntData = rot_entry->moniker->ulCntData;
179                 memcpy((*mk)->abData, rot_entry->moniker->abData, (*mk)->ulCntData);
180             }
181             else
182             {
183                 MIDL_user_free(*obj);
184                 MIDL_user_free(*mk);
185                 hr = E_OUTOFMEMORY;
186             }
187
188             rot_entry_delete(rot_entry);
189             return hr;
190         }
191     }
192     LeaveCriticalSection(&csRunningObjectTable);
193
194     return E_INVALIDARG;
195 }
196
197 HRESULT IrotIsRunning(
198     IrotHandle h,
199     const MonikerComparisonData *data)
200 {
201     const struct rot_entry *rot_entry;
202     HRESULT hr = S_FALSE;
203
204     WINE_TRACE("\n");
205
206     EnterCriticalSection(&csRunningObjectTable);
207
208     LIST_FOR_EACH_ENTRY(rot_entry, &RunningObjectTable, const struct rot_entry, entry)
209     {
210         if ((rot_entry->moniker_data->ulCntData == data->ulCntData) &&
211             !memcmp(&data->abData, &rot_entry->moniker_data->abData, data->ulCntData))
212         {
213             hr = S_OK;
214             break;
215         }
216     }
217     LeaveCriticalSection(&csRunningObjectTable);
218
219     return hr;
220 }
221
222 HRESULT IrotGetObject(
223     IrotHandle h,
224     const MonikerComparisonData *moniker_data,
225     PInterfaceData *obj,
226     IrotCookie *cookie)
227 {
228     const struct rot_entry *rot_entry;
229
230     WINE_TRACE("%p\n", moniker_data);
231
232     EnterCriticalSection(&csRunningObjectTable);
233
234     LIST_FOR_EACH_ENTRY(rot_entry, &RunningObjectTable, const struct rot_entry, entry)
235     {
236         HRESULT hr = S_OK;
237         if ((rot_entry->moniker_data->ulCntData == moniker_data->ulCntData) &&
238             !memcmp(&moniker_data->abData, &rot_entry->moniker_data->abData, moniker_data->ulCntData))
239         {
240             *obj = MIDL_user_allocate(FIELD_OFFSET(InterfaceData, abData[rot_entry->object->ulCntData]));
241             if (*obj)
242             {
243                 (*obj)->ulCntData = rot_entry->object->ulCntData;
244                 memcpy((*obj)->abData, rot_entry->object->abData, (*obj)->ulCntData);
245
246                 *cookie = rot_entry->cookie;
247             }
248             else
249                 hr = E_OUTOFMEMORY;
250
251             LeaveCriticalSection(&csRunningObjectTable);
252
253             return hr;
254         }
255     }
256
257     LeaveCriticalSection(&csRunningObjectTable);
258
259     return MK_E_UNAVAILABLE;
260 }
261
262 HRESULT IrotNoteChangeTime(
263     IrotHandle h,
264     IrotCookie cookie,
265     const FILETIME *last_modified_time)
266 {
267     struct rot_entry *rot_entry;
268
269     WINE_TRACE("%d %p\n", cookie, last_modified_time);
270
271     EnterCriticalSection(&csRunningObjectTable);
272     LIST_FOR_EACH_ENTRY(rot_entry, &RunningObjectTable, struct rot_entry, entry)
273     {
274         if (rot_entry->cookie == cookie)
275         {
276             rot_entry->last_modified = *last_modified_time;
277             LeaveCriticalSection(&csRunningObjectTable);
278             return S_OK;
279         }
280     }
281     LeaveCriticalSection(&csRunningObjectTable);
282
283     return E_INVALIDARG;
284 }
285
286 HRESULT IrotGetTimeOfLastChange(
287     IrotHandle h,
288     const MonikerComparisonData *moniker_data,
289     FILETIME *time)
290 {
291     const struct rot_entry *rot_entry;
292     HRESULT hr = MK_E_UNAVAILABLE;
293
294     WINE_TRACE("%p\n", moniker_data);
295
296     EnterCriticalSection(&csRunningObjectTable);
297     LIST_FOR_EACH_ENTRY(rot_entry, &RunningObjectTable, const struct rot_entry, entry)
298     {
299         if ((rot_entry->moniker_data->ulCntData == moniker_data->ulCntData) &&
300             !memcmp(&moniker_data->abData, &rot_entry->moniker_data->abData, moniker_data->ulCntData))
301         {
302             *time = rot_entry->last_modified;
303             hr = S_OK;
304             break;
305         }
306     }
307     LeaveCriticalSection(&csRunningObjectTable);
308
309     return hr;
310 }
311
312 HRESULT IrotEnumRunning(
313     IrotHandle h,
314     PInterfaceList *list)
315 {
316     const struct rot_entry *rot_entry;
317     HRESULT hr = S_OK;
318     ULONG moniker_count = 0;
319     ULONG i = 0;
320
321     WINE_TRACE("\n");
322
323     EnterCriticalSection(&csRunningObjectTable);
324
325     LIST_FOR_EACH_ENTRY( rot_entry, &RunningObjectTable, const struct rot_entry, entry )
326         moniker_count++;
327
328     *list = MIDL_user_allocate(FIELD_OFFSET(InterfaceList, interfaces[moniker_count]));
329     if (*list)
330     {
331         (*list)->size = moniker_count;
332         LIST_FOR_EACH_ENTRY( rot_entry, &RunningObjectTable, const struct rot_entry, entry )
333         {
334             (*list)->interfaces[i] = MIDL_user_allocate(FIELD_OFFSET(InterfaceData, abData[rot_entry->moniker->ulCntData]));
335             if (!(*list)->interfaces[i])
336             {
337                 ULONG end = i - 1;
338                 for (i = 0; i < end; i++)
339                     MIDL_user_free((*list)->interfaces[i]);
340                 MIDL_user_free(*list);
341                 hr = E_OUTOFMEMORY;
342                 break;
343             }
344             (*list)->interfaces[i]->ulCntData = rot_entry->moniker->ulCntData;
345             memcpy((*list)->interfaces[i]->abData, rot_entry->moniker->abData, rot_entry->moniker->ulCntData);
346             i++;
347         }
348     }
349     else
350         hr = E_OUTOFMEMORY;
351
352     LeaveCriticalSection(&csRunningObjectTable);
353
354     return hr;
355 }
356
357 void * __RPC_USER MIDL_user_allocate(size_t size)
358 {
359     return HeapAlloc(GetProcessHeap(), 0, size);
360 }
361
362 void __RPC_USER MIDL_user_free(void * p)
363 {
364     HeapFree(GetProcessHeap(), 0, p);
365 }