380 lines
11 KiB
C
380 lines
11 KiB
C
/*
|
|
* Running Object Table
|
|
*
|
|
* Copyright 2007 Robert Shearman
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
|
*/
|
|
|
|
#include <stdarg.h>
|
|
#include <string.h>
|
|
|
|
#include "winerror.h"
|
|
#include "windef.h"
|
|
#include "winbase.h"
|
|
|
|
#include "irot.h"
|
|
|
|
#include "wine/list.h"
|
|
#include "wine/debug.h"
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(rpcss);
|
|
|
|
/* define the structure of the running object table elements */
|
|
struct rot_entry
|
|
{
|
|
struct list entry;
|
|
InterfaceData *object; /* marshaled running object*/
|
|
InterfaceData *moniker; /* marshaled moniker that identifies this object */
|
|
MonikerComparisonData *moniker_data; /* moniker comparison data that identifies this object */
|
|
DWORD cookie; /* cookie identifying this object */
|
|
FILETIME last_modified;
|
|
LONG refs;
|
|
};
|
|
|
|
static struct list RunningObjectTable = LIST_INIT(RunningObjectTable);
|
|
|
|
static CRITICAL_SECTION csRunningObjectTable;
|
|
static CRITICAL_SECTION_DEBUG critsect_debug =
|
|
{
|
|
0, 0, &csRunningObjectTable,
|
|
{ &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
|
|
0, 0, { (DWORD_PTR)(__FILE__ ": csRunningObjectTable") }
|
|
};
|
|
static CRITICAL_SECTION csRunningObjectTable = { &critsect_debug, -1, 0, 0, 0, 0 };
|
|
|
|
static LONG last_cookie = 1;
|
|
|
|
static inline void rot_entry_release(struct rot_entry *rot_entry)
|
|
{
|
|
if (!InterlockedDecrement(&rot_entry->refs))
|
|
{
|
|
HeapFree(GetProcessHeap(), 0, rot_entry->object);
|
|
HeapFree(GetProcessHeap(), 0, rot_entry->moniker);
|
|
HeapFree(GetProcessHeap(), 0, rot_entry->moniker_data);
|
|
HeapFree(GetProcessHeap(), 0, rot_entry);
|
|
}
|
|
}
|
|
|
|
HRESULT __cdecl IrotRegister(
|
|
IrotHandle h,
|
|
const MonikerComparisonData *data,
|
|
const InterfaceData *obj,
|
|
const InterfaceData *mk,
|
|
const FILETIME *time,
|
|
DWORD grfFlags,
|
|
IrotCookie *cookie,
|
|
IrotContextHandle *ctxt_handle)
|
|
{
|
|
struct rot_entry *rot_entry;
|
|
struct rot_entry *existing_rot_entry;
|
|
HRESULT hr;
|
|
|
|
if (grfFlags & ~(ROTFLAGS_REGISTRATIONKEEPSALIVE|ROTFLAGS_ALLOWANYCLIENT))
|
|
{
|
|
WINE_ERR("Invalid grfFlags: 0x%08x\n", grfFlags & ~(ROTFLAGS_REGISTRATIONKEEPSALIVE|ROTFLAGS_ALLOWANYCLIENT));
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
rot_entry = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*rot_entry));
|
|
if (!rot_entry)
|
|
return E_OUTOFMEMORY;
|
|
|
|
rot_entry->refs = 1;
|
|
rot_entry->object = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(InterfaceData, abData[obj->ulCntData]));
|
|
if (!rot_entry->object)
|
|
{
|
|
rot_entry_release(rot_entry);
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
rot_entry->object->ulCntData = obj->ulCntData;
|
|
memcpy(&rot_entry->object->abData, obj->abData, obj->ulCntData);
|
|
|
|
rot_entry->last_modified = *time;
|
|
|
|
rot_entry->moniker = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(InterfaceData, abData[mk->ulCntData]));
|
|
if (!rot_entry->moniker)
|
|
{
|
|
rot_entry_release(rot_entry);
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
rot_entry->moniker->ulCntData = mk->ulCntData;
|
|
memcpy(&rot_entry->moniker->abData, mk->abData, mk->ulCntData);
|
|
|
|
rot_entry->moniker_data = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(MonikerComparisonData, abData[data->ulCntData]));
|
|
if (!rot_entry->moniker_data)
|
|
{
|
|
rot_entry_release(rot_entry);
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
rot_entry->moniker_data->ulCntData = data->ulCntData;
|
|
memcpy(&rot_entry->moniker_data->abData, data->abData, data->ulCntData);
|
|
|
|
EnterCriticalSection(&csRunningObjectTable);
|
|
|
|
hr = S_OK;
|
|
|
|
LIST_FOR_EACH_ENTRY(existing_rot_entry, &RunningObjectTable, struct rot_entry, entry)
|
|
{
|
|
if ((existing_rot_entry->moniker_data->ulCntData == data->ulCntData) &&
|
|
!memcmp(&data->abData, &existing_rot_entry->moniker_data->abData, data->ulCntData))
|
|
{
|
|
hr = MK_S_MONIKERALREADYREGISTERED;
|
|
WINE_TRACE("moniker already registered with cookie %d\n", existing_rot_entry->cookie);
|
|
break;
|
|
}
|
|
}
|
|
|
|
list_add_tail(&RunningObjectTable, &rot_entry->entry);
|
|
|
|
LeaveCriticalSection(&csRunningObjectTable);
|
|
|
|
/* gives a registration identifier to the registered object*/
|
|
*cookie = rot_entry->cookie = InterlockedIncrement(&last_cookie);
|
|
*ctxt_handle = rot_entry;
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT __cdecl IrotRevoke(
|
|
IrotHandle h,
|
|
IrotCookie cookie,
|
|
IrotContextHandle *ctxt_handle,
|
|
PInterfaceData *obj,
|
|
PInterfaceData *mk)
|
|
{
|
|
struct rot_entry *rot_entry;
|
|
|
|
WINE_TRACE("%d\n", cookie);
|
|
|
|
EnterCriticalSection(&csRunningObjectTable);
|
|
LIST_FOR_EACH_ENTRY(rot_entry, &RunningObjectTable, struct rot_entry, entry)
|
|
{
|
|
if (rot_entry->cookie == cookie)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
list_remove(&rot_entry->entry);
|
|
LeaveCriticalSection(&csRunningObjectTable);
|
|
|
|
*obj = MIDL_user_allocate(FIELD_OFFSET(InterfaceData, abData[rot_entry->object->ulCntData]));
|
|
*mk = MIDL_user_allocate(FIELD_OFFSET(InterfaceData, abData[rot_entry->moniker->ulCntData]));
|
|
if (*obj && *mk)
|
|
{
|
|
(*obj)->ulCntData = rot_entry->object->ulCntData;
|
|
memcpy((*obj)->abData, rot_entry->object->abData, (*obj)->ulCntData);
|
|
(*mk)->ulCntData = rot_entry->moniker->ulCntData;
|
|
memcpy((*mk)->abData, rot_entry->moniker->abData, (*mk)->ulCntData);
|
|
}
|
|
else
|
|
{
|
|
MIDL_user_free(*obj);
|
|
MIDL_user_free(*mk);
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
|
|
rot_entry_release(rot_entry);
|
|
*ctxt_handle = NULL;
|
|
return hr;
|
|
}
|
|
}
|
|
LeaveCriticalSection(&csRunningObjectTable);
|
|
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
HRESULT __cdecl IrotIsRunning(
|
|
IrotHandle h,
|
|
const MonikerComparisonData *data)
|
|
{
|
|
const struct rot_entry *rot_entry;
|
|
HRESULT hr = S_FALSE;
|
|
|
|
WINE_TRACE("\n");
|
|
|
|
EnterCriticalSection(&csRunningObjectTable);
|
|
|
|
LIST_FOR_EACH_ENTRY(rot_entry, &RunningObjectTable, const struct rot_entry, entry)
|
|
{
|
|
if ((rot_entry->moniker_data->ulCntData == data->ulCntData) &&
|
|
!memcmp(&data->abData, &rot_entry->moniker_data->abData, data->ulCntData))
|
|
{
|
|
hr = S_OK;
|
|
break;
|
|
}
|
|
}
|
|
LeaveCriticalSection(&csRunningObjectTable);
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT __cdecl IrotGetObject(
|
|
IrotHandle h,
|
|
const MonikerComparisonData *moniker_data,
|
|
PInterfaceData *obj,
|
|
IrotCookie *cookie)
|
|
{
|
|
const struct rot_entry *rot_entry;
|
|
|
|
WINE_TRACE("%p\n", moniker_data);
|
|
|
|
*cookie = 0;
|
|
|
|
EnterCriticalSection(&csRunningObjectTable);
|
|
|
|
LIST_FOR_EACH_ENTRY(rot_entry, &RunningObjectTable, const struct rot_entry, entry)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
if ((rot_entry->moniker_data->ulCntData == moniker_data->ulCntData) &&
|
|
!memcmp(&moniker_data->abData, &rot_entry->moniker_data->abData, moniker_data->ulCntData))
|
|
{
|
|
*obj = MIDL_user_allocate(FIELD_OFFSET(InterfaceData, abData[rot_entry->object->ulCntData]));
|
|
if (*obj)
|
|
{
|
|
(*obj)->ulCntData = rot_entry->object->ulCntData;
|
|
memcpy((*obj)->abData, rot_entry->object->abData, (*obj)->ulCntData);
|
|
|
|
*cookie = rot_entry->cookie;
|
|
}
|
|
else
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
LeaveCriticalSection(&csRunningObjectTable);
|
|
|
|
return hr;
|
|
}
|
|
}
|
|
|
|
LeaveCriticalSection(&csRunningObjectTable);
|
|
|
|
return MK_E_UNAVAILABLE;
|
|
}
|
|
|
|
HRESULT __cdecl IrotNoteChangeTime(
|
|
IrotHandle h,
|
|
IrotCookie cookie,
|
|
const FILETIME *last_modified_time)
|
|
{
|
|
struct rot_entry *rot_entry;
|
|
|
|
WINE_TRACE("%d %p\n", cookie, last_modified_time);
|
|
|
|
EnterCriticalSection(&csRunningObjectTable);
|
|
LIST_FOR_EACH_ENTRY(rot_entry, &RunningObjectTable, struct rot_entry, entry)
|
|
{
|
|
if (rot_entry->cookie == cookie)
|
|
{
|
|
rot_entry->last_modified = *last_modified_time;
|
|
LeaveCriticalSection(&csRunningObjectTable);
|
|
return S_OK;
|
|
}
|
|
}
|
|
LeaveCriticalSection(&csRunningObjectTable);
|
|
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
HRESULT __cdecl IrotGetTimeOfLastChange(
|
|
IrotHandle h,
|
|
const MonikerComparisonData *moniker_data,
|
|
FILETIME *time)
|
|
{
|
|
const struct rot_entry *rot_entry;
|
|
HRESULT hr = MK_E_UNAVAILABLE;
|
|
|
|
WINE_TRACE("%p\n", moniker_data);
|
|
|
|
memset(time, 0, sizeof(*time));
|
|
|
|
EnterCriticalSection(&csRunningObjectTable);
|
|
LIST_FOR_EACH_ENTRY(rot_entry, &RunningObjectTable, const struct rot_entry, entry)
|
|
{
|
|
if ((rot_entry->moniker_data->ulCntData == moniker_data->ulCntData) &&
|
|
!memcmp(&moniker_data->abData, &rot_entry->moniker_data->abData, moniker_data->ulCntData))
|
|
{
|
|
*time = rot_entry->last_modified;
|
|
hr = S_OK;
|
|
break;
|
|
}
|
|
}
|
|
LeaveCriticalSection(&csRunningObjectTable);
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT __cdecl IrotEnumRunning(
|
|
IrotHandle h,
|
|
PInterfaceList *list)
|
|
{
|
|
const struct rot_entry *rot_entry;
|
|
HRESULT hr = S_OK;
|
|
ULONG moniker_count = 0;
|
|
ULONG i = 0;
|
|
|
|
WINE_TRACE("\n");
|
|
|
|
EnterCriticalSection(&csRunningObjectTable);
|
|
|
|
LIST_FOR_EACH_ENTRY( rot_entry, &RunningObjectTable, const struct rot_entry, entry )
|
|
moniker_count++;
|
|
|
|
*list = MIDL_user_allocate(FIELD_OFFSET(InterfaceList, interfaces[moniker_count]));
|
|
if (*list)
|
|
{
|
|
(*list)->size = moniker_count;
|
|
LIST_FOR_EACH_ENTRY( rot_entry, &RunningObjectTable, const struct rot_entry, entry )
|
|
{
|
|
(*list)->interfaces[i] = MIDL_user_allocate(FIELD_OFFSET(InterfaceData, abData[rot_entry->moniker->ulCntData]));
|
|
if (!(*list)->interfaces[i])
|
|
{
|
|
ULONG end = i - 1;
|
|
for (i = 0; i < end; i++)
|
|
MIDL_user_free((*list)->interfaces[i]);
|
|
MIDL_user_free(*list);
|
|
hr = E_OUTOFMEMORY;
|
|
break;
|
|
}
|
|
(*list)->interfaces[i]->ulCntData = rot_entry->moniker->ulCntData;
|
|
memcpy((*list)->interfaces[i]->abData, rot_entry->moniker->abData, rot_entry->moniker->ulCntData);
|
|
i++;
|
|
}
|
|
}
|
|
else
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
LeaveCriticalSection(&csRunningObjectTable);
|
|
|
|
return hr;
|
|
}
|
|
|
|
void __RPC_USER IrotContextHandle_rundown(IrotContextHandle ctxt_handle)
|
|
{
|
|
struct rot_entry *rot_entry = ctxt_handle;
|
|
EnterCriticalSection(&csRunningObjectTable);
|
|
list_remove(&rot_entry->entry);
|
|
LeaveCriticalSection(&csRunningObjectTable);
|
|
rot_entry_release(rot_entry);
|
|
}
|
|
|
|
void * __RPC_USER MIDL_user_allocate(SIZE_T size)
|
|
{
|
|
return HeapAlloc(GetProcessHeap(), 0, size);
|
|
}
|
|
|
|
void __RPC_USER MIDL_user_free(void * p)
|
|
{
|
|
HeapFree(GetProcessHeap(), 0, p);
|
|
}
|