ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

rpc.c
Go to the documentation of this file.
00001 /*
00002  *  RPC Manager
00003  *
00004  * Copyright 2001  Ove Kåven, TransGaming Technologies
00005  * Copyright 2002  Marcus Meissner
00006  * Copyright 2005  Mike Hearn, Rob Shearman for CodeWeavers
00007  *
00008  * This library is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU Lesser General Public
00010  * License as published by the Free Software Foundation; either
00011  * version 2.1 of the License, or (at your option) any later version.
00012  *
00013  * This library is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016  * Lesser General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU Lesser General Public
00019  * License along with this library; if not, write to the Free Software
00020  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00021  */
00022 
00023 #include "config.h"
00024 #include "wine/port.h"
00025 
00026 #include <stdarg.h>
00027 #include <string.h>
00028 
00029 #define COBJMACROS
00030 #define NONAMELESSUNION
00031 #define NONAMELESSSTRUCT
00032 
00033 #include "windef.h"
00034 #include "winbase.h"
00035 #include "winuser.h"
00036 #include "winsvc.h"
00037 #include "objbase.h"
00038 #include "ole2.h"
00039 #include "rpc.h"
00040 #include "winerror.h"
00041 #include "winreg.h"
00042 #include "wine/unicode.h"
00043 
00044 #include "compobj_private.h"
00045 
00046 #include "wine/debug.h"
00047 
00048 WINE_DEFAULT_DEBUG_CHANNEL(ole);
00049 
00050 static void __RPC_STUB dispatch_rpc(RPC_MESSAGE *msg);
00051 
00052 /* we only use one function to dispatch calls for all methods - we use the
00053  * RPC_IF_OLE flag to tell the RPC runtime that this is the case */
00054 static RPC_DISPATCH_FUNCTION rpc_dispatch_table[1] = { dispatch_rpc }; /* (RO) */
00055 static RPC_DISPATCH_TABLE rpc_dispatch = { 1, rpc_dispatch_table }; /* (RO) */
00056 
00057 static struct list registered_interfaces = LIST_INIT(registered_interfaces); /* (CS csRegIf) */
00058 static CRITICAL_SECTION csRegIf;
00059 static CRITICAL_SECTION_DEBUG csRegIf_debug =
00060 {
00061     0, 0, &csRegIf,
00062     { &csRegIf_debug.ProcessLocksList, &csRegIf_debug.ProcessLocksList },
00063       0, 0, { (DWORD_PTR)(__FILE__ ": dcom registered server interfaces") }
00064 };
00065 static CRITICAL_SECTION csRegIf = { &csRegIf_debug, -1, 0, 0, 0, 0 };
00066 
00067 static struct list channel_hooks = LIST_INIT(channel_hooks); /* (CS csChannelHook) */
00068 static CRITICAL_SECTION csChannelHook;
00069 static CRITICAL_SECTION_DEBUG csChannelHook_debug =
00070 {
00071     0, 0, &csChannelHook,
00072     { &csChannelHook_debug.ProcessLocksList, &csChannelHook_debug.ProcessLocksList },
00073       0, 0, { (DWORD_PTR)(__FILE__ ": channel hooks") }
00074 };
00075 static CRITICAL_SECTION csChannelHook = { &csChannelHook_debug, -1, 0, 0, 0, 0 };
00076 
00077 static WCHAR wszRpcTransport[] = {'n','c','a','l','r','p','c',0};
00078 
00079 
00080 struct registered_if
00081 {
00082     struct list entry;
00083     DWORD refs; /* ref count */
00084     RPC_SERVER_INTERFACE If; /* interface registered with the RPC runtime */
00085 };
00086 
00087 /* get the pipe endpoint specified of the specified apartment */
00088 static inline void get_rpc_endpoint(LPWSTR endpoint, const OXID *oxid)
00089 {
00090     /* FIXME: should get endpoint from rpcss */
00091     static const WCHAR wszEndpointFormat[] = {'\\','p','i','p','e','\\','O','L','E','_','%','0','8','l','x','%','0','8','l','x',0};
00092     wsprintfW(endpoint, wszEndpointFormat, (DWORD)(*oxid >> 32),(DWORD)*oxid);
00093 }
00094 
00095 typedef struct
00096 {
00097     const IRpcChannelBufferVtbl *lpVtbl;
00098     LONG                  refs;
00099 } RpcChannelBuffer;
00100 
00101 typedef struct
00102 {
00103     RpcChannelBuffer       super; /* superclass */
00104 
00105     RPC_BINDING_HANDLE     bind; /* handle to the remote server */
00106     OXID                   oxid; /* apartment in which the channel is valid */
00107     DWORD                  server_pid; /* id of server process */
00108     DWORD                  dest_context; /* returned from GetDestCtx */
00109     LPVOID                 dest_context_data; /* returned from GetDestCtx */
00110     HANDLE                 event; /* cached event handle */
00111 } ClientRpcChannelBuffer;
00112 
00113 struct dispatch_params
00114 {
00115     RPCOLEMESSAGE     *msg; /* message */
00116     IRpcStubBuffer    *stub; /* stub buffer, if applicable */
00117     IRpcChannelBuffer *chan; /* server channel buffer, if applicable */
00118     IID                iid; /* ID of interface being called */
00119     IUnknown          *iface; /* interface being called */
00120     HANDLE             handle; /* handle that will become signaled when call finishes */
00121     BOOL               bypass_rpcrt; /* bypass RPC runtime? */
00122     RPC_STATUS         status; /* status (out) */
00123     HRESULT            hr; /* hresult (out) */
00124 };
00125 
00126 struct message_state
00127 {
00128     RPC_BINDING_HANDLE binding_handle;
00129     ULONG prefix_data_len;
00130     SChannelHookCallInfo channel_hook_info;
00131     BOOL bypass_rpcrt;
00132 
00133     /* client only */
00134     HWND target_hwnd;
00135     DWORD target_tid;
00136     struct dispatch_params params;
00137 };
00138 
00139 typedef struct
00140 {
00141     ULONG conformance; /* NDR */
00142     GUID id;
00143     ULONG size;
00144     /* [size_is((size+7)&~7)] */ unsigned char data[1];
00145 } WIRE_ORPC_EXTENT;
00146 
00147 typedef struct
00148 {
00149     ULONG size;
00150     ULONG reserved;
00151     unsigned char extent[1];
00152 } WIRE_ORPC_EXTENT_ARRAY;
00153 
00154 typedef struct
00155 {
00156     ULONG version;
00157     ULONG flags;
00158     ULONG reserved1;
00159     GUID  cid;
00160     unsigned char extensions[1];
00161 } WIRE_ORPCTHIS;
00162 
00163 typedef struct
00164 {
00165     ULONG flags;
00166     unsigned char extensions[1];
00167 } WIRE_ORPCTHAT;
00168 
00169 struct channel_hook_entry
00170 {
00171     struct list entry;
00172     GUID id;
00173     IChannelHook *hook;
00174 };
00175 
00176 struct channel_hook_buffer_data
00177 {
00178     GUID id;
00179     ULONG extension_size;
00180 };
00181 
00182 
00183 static HRESULT unmarshal_ORPCTHAT(RPC_MESSAGE *msg, ORPCTHAT *orpcthat,
00184                                   ORPC_EXTENT_ARRAY *orpc_ext_array, WIRE_ORPC_EXTENT **first_wire_orpc_extent);
00185 
00186 /* Channel Hook Functions */
00187 
00188 static ULONG ChannelHooks_ClientGetSize(SChannelHookCallInfo *info,
00189     struct channel_hook_buffer_data **data, unsigned int *hook_count,
00190     ULONG *extension_count)
00191 {
00192     struct channel_hook_entry *entry;
00193     ULONG total_size = 0;
00194     unsigned int hook_index = 0;
00195 
00196     *hook_count = 0;
00197     *extension_count = 0;
00198 
00199     EnterCriticalSection(&csChannelHook);
00200 
00201     LIST_FOR_EACH_ENTRY(entry, &channel_hooks, struct channel_hook_entry, entry)
00202         (*hook_count)++;
00203 
00204     if (*hook_count)
00205         *data = HeapAlloc(GetProcessHeap(), 0, *hook_count * sizeof(struct channel_hook_buffer_data));
00206     else
00207         *data = NULL;
00208 
00209     LIST_FOR_EACH_ENTRY(entry, &channel_hooks, struct channel_hook_entry, entry)
00210     {
00211         ULONG extension_size = 0;
00212 
00213         IChannelHook_ClientGetSize(entry->hook, &entry->id, &info->iid, &extension_size);
00214 
00215         TRACE("%s: extension_size = %u\n", debugstr_guid(&entry->id), extension_size);
00216 
00217         extension_size = (extension_size+7)&~7;
00218         (*data)[hook_index].id = entry->id;
00219         (*data)[hook_index].extension_size = extension_size;
00220 
00221         /* an extension is only put onto the wire if it has data to write */
00222         if (extension_size)
00223         {
00224             total_size += FIELD_OFFSET(WIRE_ORPC_EXTENT, data[extension_size]);
00225             (*extension_count)++;
00226         }
00227 
00228         hook_index++;
00229     }
00230 
00231     LeaveCriticalSection(&csChannelHook);
00232 
00233     return total_size;
00234 }
00235 
00236 static unsigned char * ChannelHooks_ClientFillBuffer(SChannelHookCallInfo *info,
00237     unsigned char *buffer, struct channel_hook_buffer_data *data,
00238     unsigned int hook_count)
00239 {
00240     struct channel_hook_entry *entry;
00241 
00242     EnterCriticalSection(&csChannelHook);
00243 
00244     LIST_FOR_EACH_ENTRY(entry, &channel_hooks, struct channel_hook_entry, entry)
00245     {
00246         unsigned int i;
00247         ULONG extension_size = 0;
00248         WIRE_ORPC_EXTENT *wire_orpc_extent = (WIRE_ORPC_EXTENT *)buffer;
00249 
00250         for (i = 0; i < hook_count; i++)
00251             if (IsEqualGUID(&entry->id, &data[i].id))
00252                 extension_size = data[i].extension_size;
00253 
00254         /* an extension is only put onto the wire if it has data to write */
00255         if (!extension_size)
00256             continue;
00257 
00258         IChannelHook_ClientFillBuffer(entry->hook, &entry->id, &info->iid,
00259             &extension_size, buffer + FIELD_OFFSET(WIRE_ORPC_EXTENT, data[0]));
00260 
00261         TRACE("%s: extension_size = %u\n", debugstr_guid(&entry->id), extension_size);
00262 
00263         /* FIXME: set unused portion of wire_orpc_extent->data to 0? */
00264 
00265         wire_orpc_extent->conformance = (extension_size+7)&~7;
00266         wire_orpc_extent->size = extension_size;
00267         wire_orpc_extent->id = entry->id;
00268         buffer += FIELD_OFFSET(WIRE_ORPC_EXTENT, data[wire_orpc_extent->conformance]);
00269     }
00270 
00271     LeaveCriticalSection(&csChannelHook);
00272 
00273     return buffer;
00274 }
00275 
00276 static void ChannelHooks_ServerNotify(SChannelHookCallInfo *info,
00277     DWORD lDataRep, WIRE_ORPC_EXTENT *first_wire_orpc_extent,
00278     ULONG extension_count)
00279 {
00280     struct channel_hook_entry *entry;
00281     ULONG i;
00282 
00283     EnterCriticalSection(&csChannelHook);
00284 
00285     LIST_FOR_EACH_ENTRY(entry, &channel_hooks, struct channel_hook_entry, entry)
00286     {
00287         WIRE_ORPC_EXTENT *wire_orpc_extent;
00288         for (i = 0, wire_orpc_extent = first_wire_orpc_extent;
00289              i < extension_count;
00290              i++, wire_orpc_extent = (WIRE_ORPC_EXTENT *)&wire_orpc_extent->data[wire_orpc_extent->conformance])
00291         {
00292             if (IsEqualGUID(&entry->id, &wire_orpc_extent->id))
00293                 break;
00294         }
00295         if (i == extension_count) wire_orpc_extent = NULL;
00296 
00297         IChannelHook_ServerNotify(entry->hook, &entry->id, &info->iid,
00298             wire_orpc_extent ? wire_orpc_extent->size : 0,
00299             wire_orpc_extent ? wire_orpc_extent->data : NULL,
00300             lDataRep);
00301     }
00302 
00303     LeaveCriticalSection(&csChannelHook);
00304 }
00305 
00306 static ULONG ChannelHooks_ServerGetSize(SChannelHookCallInfo *info,
00307                                         struct channel_hook_buffer_data **data, unsigned int *hook_count,
00308                                         ULONG *extension_count)
00309 {
00310     struct channel_hook_entry *entry;
00311     ULONG total_size = 0;
00312     unsigned int hook_index = 0;
00313 
00314     *hook_count = 0;
00315     *extension_count = 0;
00316 
00317     EnterCriticalSection(&csChannelHook);
00318 
00319     LIST_FOR_EACH_ENTRY(entry, &channel_hooks, struct channel_hook_entry, entry)
00320         (*hook_count)++;
00321 
00322     if (*hook_count)
00323         *data = HeapAlloc(GetProcessHeap(), 0, *hook_count * sizeof(struct channel_hook_buffer_data));
00324     else
00325         *data = NULL;
00326 
00327     LIST_FOR_EACH_ENTRY(entry, &channel_hooks, struct channel_hook_entry, entry)
00328     {
00329         ULONG extension_size = 0;
00330 
00331         IChannelHook_ServerGetSize(entry->hook, &entry->id, &info->iid, S_OK,
00332                                    &extension_size);
00333 
00334         TRACE("%s: extension_size = %u\n", debugstr_guid(&entry->id), extension_size);
00335 
00336         extension_size = (extension_size+7)&~7;
00337         (*data)[hook_index].id = entry->id;
00338         (*data)[hook_index].extension_size = extension_size;
00339 
00340         /* an extension is only put onto the wire if it has data to write */
00341         if (extension_size)
00342         {
00343             total_size += FIELD_OFFSET(WIRE_ORPC_EXTENT, data[extension_size]);
00344             (*extension_count)++;
00345         }
00346 
00347         hook_index++;
00348     }
00349 
00350     LeaveCriticalSection(&csChannelHook);
00351 
00352     return total_size;
00353 }
00354 
00355 static unsigned char * ChannelHooks_ServerFillBuffer(SChannelHookCallInfo *info,
00356                                                      unsigned char *buffer, struct channel_hook_buffer_data *data,
00357                                                      unsigned int hook_count)
00358 {
00359     struct channel_hook_entry *entry;
00360 
00361     EnterCriticalSection(&csChannelHook);
00362 
00363     LIST_FOR_EACH_ENTRY(entry, &channel_hooks, struct channel_hook_entry, entry)
00364     {
00365         unsigned int i;
00366         ULONG extension_size = 0;
00367         WIRE_ORPC_EXTENT *wire_orpc_extent = (WIRE_ORPC_EXTENT *)buffer;
00368 
00369         for (i = 0; i < hook_count; i++)
00370             if (IsEqualGUID(&entry->id, &data[i].id))
00371                 extension_size = data[i].extension_size;
00372 
00373         /* an extension is only put onto the wire if it has data to write */
00374         if (!extension_size)
00375             continue;
00376 
00377         IChannelHook_ServerFillBuffer(entry->hook, &entry->id, &info->iid,
00378                                       &extension_size, buffer + FIELD_OFFSET(WIRE_ORPC_EXTENT, data[0]),
00379                                       S_OK);
00380 
00381         TRACE("%s: extension_size = %u\n", debugstr_guid(&entry->id), extension_size);
00382 
00383         /* FIXME: set unused portion of wire_orpc_extent->data to 0? */
00384 
00385         wire_orpc_extent->conformance = (extension_size+7)&~7;
00386         wire_orpc_extent->size = extension_size;
00387         wire_orpc_extent->id = entry->id;
00388         buffer += FIELD_OFFSET(WIRE_ORPC_EXTENT, data[wire_orpc_extent->conformance]);
00389     }
00390 
00391     LeaveCriticalSection(&csChannelHook);
00392 
00393     return buffer;
00394 }
00395 
00396 static void ChannelHooks_ClientNotify(SChannelHookCallInfo *info,
00397                                       DWORD lDataRep, WIRE_ORPC_EXTENT *first_wire_orpc_extent,
00398                                       ULONG extension_count, HRESULT hrFault)
00399 {
00400     struct channel_hook_entry *entry;
00401     ULONG i;
00402 
00403     EnterCriticalSection(&csChannelHook);
00404 
00405     LIST_FOR_EACH_ENTRY(entry, &channel_hooks, struct channel_hook_entry, entry)
00406     {
00407         WIRE_ORPC_EXTENT *wire_orpc_extent;
00408         for (i = 0, wire_orpc_extent = first_wire_orpc_extent;
00409              i < extension_count;
00410              i++, wire_orpc_extent = (WIRE_ORPC_EXTENT *)&wire_orpc_extent->data[wire_orpc_extent->conformance])
00411         {
00412             if (IsEqualGUID(&entry->id, &wire_orpc_extent->id))
00413                 break;
00414         }
00415         if (i == extension_count) wire_orpc_extent = NULL;
00416 
00417         IChannelHook_ClientNotify(entry->hook, &entry->id, &info->iid,
00418                                   wire_orpc_extent ? wire_orpc_extent->size : 0,
00419                                   wire_orpc_extent ? wire_orpc_extent->data : NULL,
00420                                   lDataRep, hrFault);
00421     }
00422 
00423     LeaveCriticalSection(&csChannelHook);
00424 }
00425 
00426 HRESULT RPC_RegisterChannelHook(REFGUID rguid, IChannelHook *hook)
00427 {
00428     struct channel_hook_entry *entry;
00429 
00430     TRACE("(%s, %p)\n", debugstr_guid(rguid), hook);
00431 
00432     entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*entry));
00433     if (!entry)
00434         return E_OUTOFMEMORY;
00435 
00436     entry->id = *rguid;
00437     entry->hook = hook;
00438     IChannelHook_AddRef(hook);
00439 
00440     EnterCriticalSection(&csChannelHook);
00441     list_add_tail(&channel_hooks, &entry->entry);
00442     LeaveCriticalSection(&csChannelHook);
00443 
00444     return S_OK;
00445 }
00446 
00447 void RPC_UnregisterAllChannelHooks(void)
00448 {
00449     struct channel_hook_entry *cursor;
00450     struct channel_hook_entry *cursor2;
00451 
00452     EnterCriticalSection(&csChannelHook);
00453     LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, &channel_hooks, struct channel_hook_entry, entry)
00454         HeapFree(GetProcessHeap(), 0, cursor);
00455     LeaveCriticalSection(&csChannelHook);
00456     DeleteCriticalSection(&csChannelHook);
00457     DeleteCriticalSection(&csRegIf);
00458 }
00459 
00460 /* RPC Channel Buffer Functions */
00461 
00462 static HRESULT WINAPI RpcChannelBuffer_QueryInterface(LPRPCCHANNELBUFFER iface, REFIID riid, LPVOID *ppv)
00463 {
00464     *ppv = NULL;
00465     if (IsEqualIID(riid,&IID_IRpcChannelBuffer) || IsEqualIID(riid,&IID_IUnknown))
00466     {
00467         *ppv = iface;
00468         IUnknown_AddRef(iface);
00469         return S_OK;
00470     }
00471     return E_NOINTERFACE;
00472 }
00473 
00474 static ULONG WINAPI RpcChannelBuffer_AddRef(LPRPCCHANNELBUFFER iface)
00475 {
00476     RpcChannelBuffer *This = (RpcChannelBuffer *)iface;
00477     return InterlockedIncrement(&This->refs);
00478 }
00479 
00480 static ULONG WINAPI ServerRpcChannelBuffer_Release(LPRPCCHANNELBUFFER iface)
00481 {
00482     RpcChannelBuffer *This = (RpcChannelBuffer *)iface;
00483     ULONG ref;
00484 
00485     ref = InterlockedDecrement(&This->refs);
00486     if (ref)
00487         return ref;
00488 
00489     HeapFree(GetProcessHeap(), 0, This);
00490     return 0;
00491 }
00492 
00493 static ULONG WINAPI ClientRpcChannelBuffer_Release(LPRPCCHANNELBUFFER iface)
00494 {
00495     ClientRpcChannelBuffer *This = (ClientRpcChannelBuffer *)iface;
00496     ULONG ref;
00497 
00498     ref = InterlockedDecrement(&This->super.refs);
00499     if (ref)
00500         return ref;
00501 
00502     if (This->event) CloseHandle(This->event);
00503     RpcBindingFree(&This->bind);
00504     HeapFree(GetProcessHeap(), 0, This);
00505     return 0;
00506 }
00507 
00508 static HRESULT WINAPI ServerRpcChannelBuffer_GetBuffer(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE* olemsg, REFIID riid)
00509 {
00510     RpcChannelBuffer *This = (RpcChannelBuffer *)iface;
00511     RPC_MESSAGE *msg = (RPC_MESSAGE *)olemsg;
00512     RPC_STATUS status;
00513     ORPCTHAT *orpcthat;
00514     struct message_state *message_state;
00515     ULONG extensions_size;
00516     struct channel_hook_buffer_data *channel_hook_data;
00517     unsigned int channel_hook_count;
00518     ULONG extension_count;
00519 
00520     TRACE("(%p)->(%p,%s)\n", This, olemsg, debugstr_guid(riid));
00521 
00522     message_state = msg->Handle;
00523     /* restore the binding handle and the real start of data */
00524     msg->Handle = message_state->binding_handle;
00525     msg->Buffer = (char *)msg->Buffer - message_state->prefix_data_len;
00526 
00527     extensions_size = ChannelHooks_ServerGetSize(&message_state->channel_hook_info,
00528                                                  &channel_hook_data, &channel_hook_count, &extension_count);
00529 
00530     msg->BufferLength += FIELD_OFFSET(WIRE_ORPCTHAT, extensions) + sizeof(DWORD);
00531     if (extensions_size)
00532     {
00533         msg->BufferLength += FIELD_OFFSET(WIRE_ORPC_EXTENT_ARRAY, extent[2*sizeof(DWORD) + extensions_size]);
00534         if (extension_count & 1)
00535             msg->BufferLength += FIELD_OFFSET(WIRE_ORPC_EXTENT, data[0]);
00536     }
00537 
00538     if (message_state->bypass_rpcrt)
00539     {
00540         msg->Buffer = HeapAlloc(GetProcessHeap(), 0, msg->BufferLength);
00541         if (msg->Buffer)
00542             status = RPC_S_OK;
00543         else
00544         {
00545             HeapFree(GetProcessHeap(), 0, channel_hook_data);
00546             return E_OUTOFMEMORY;
00547         }
00548     }
00549     else
00550         status = I_RpcGetBuffer(msg);
00551 
00552     orpcthat = msg->Buffer;
00553     msg->Buffer = (char *)msg->Buffer + FIELD_OFFSET(WIRE_ORPCTHAT, extensions);
00554 
00555     orpcthat->flags = ORPCF_NULL /* FIXME? */;
00556 
00557     /* NDR representation of orpcthat->extensions */
00558     *(DWORD *)msg->Buffer = extensions_size ? 1 : 0;
00559     msg->Buffer = (char *)msg->Buffer + sizeof(DWORD);
00560 
00561     if (extensions_size)
00562     {
00563         WIRE_ORPC_EXTENT_ARRAY *orpc_extent_array = msg->Buffer;
00564         orpc_extent_array->size = extension_count;
00565         orpc_extent_array->reserved = 0;
00566         msg->Buffer = (char *)msg->Buffer + FIELD_OFFSET(WIRE_ORPC_EXTENT_ARRAY, extent);
00567         /* NDR representation of orpc_extent_array->extent */
00568         *(DWORD *)msg->Buffer = 1;
00569         msg->Buffer = (char *)msg->Buffer + sizeof(DWORD);
00570         /* NDR representation of [size_is] attribute of orpc_extent_array->extent */
00571         *(DWORD *)msg->Buffer = (extension_count + 1) & ~1;
00572         msg->Buffer = (char *)msg->Buffer + sizeof(DWORD);
00573 
00574         msg->Buffer = ChannelHooks_ServerFillBuffer(&message_state->channel_hook_info,
00575                                                     msg->Buffer, channel_hook_data, channel_hook_count);
00576 
00577         /* we must add a dummy extension if there is an odd extension
00578          * count to meet the contract specified by the size_is attribute */
00579         if (extension_count & 1)
00580         {
00581             WIRE_ORPC_EXTENT *wire_orpc_extent = msg->Buffer;
00582             wire_orpc_extent->conformance = 0;
00583             wire_orpc_extent->id = GUID_NULL;
00584             wire_orpc_extent->size = 0;
00585             msg->Buffer = (char *)msg->Buffer + FIELD_OFFSET(WIRE_ORPC_EXTENT, data[0]);
00586         }
00587     }
00588 
00589     HeapFree(GetProcessHeap(), 0, channel_hook_data);
00590 
00591     /* store the prefixed data length so that we can restore the real buffer
00592      * later */
00593     message_state->prefix_data_len = (char *)msg->Buffer - (char *)orpcthat;
00594     msg->BufferLength -= message_state->prefix_data_len;
00595     /* save away the message state again */
00596     msg->Handle = message_state;
00597 
00598     TRACE("-- %d\n", status);
00599 
00600     return HRESULT_FROM_WIN32(status);
00601 }
00602 
00603 static HANDLE ClientRpcChannelBuffer_GetEventHandle(ClientRpcChannelBuffer *This)
00604 {
00605     HANDLE event = InterlockedExchangePointer(&This->event, NULL);
00606 
00607     /* Note: must be auto-reset event so we can reuse it without a call
00608     * to ResetEvent */
00609     if (!event) event = CreateEventW(NULL, FALSE, FALSE, NULL);
00610 
00611     return event;
00612 }
00613 
00614 static void ClientRpcChannelBuffer_ReleaseEventHandle(ClientRpcChannelBuffer *This, HANDLE event)
00615 {
00616     if (InterlockedCompareExchangePointer(&This->event, event, NULL))
00617         /* already a handle cached in This */
00618         CloseHandle(event);
00619 }
00620 
00621 static HRESULT WINAPI ClientRpcChannelBuffer_GetBuffer(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE* olemsg, REFIID riid)
00622 {
00623     ClientRpcChannelBuffer *This = (ClientRpcChannelBuffer *)iface;
00624     RPC_MESSAGE *msg = (RPC_MESSAGE *)olemsg;
00625     RPC_CLIENT_INTERFACE *cif;
00626     RPC_STATUS status;
00627     ORPCTHIS *orpcthis;
00628     struct message_state *message_state;
00629     ULONG extensions_size;
00630     struct channel_hook_buffer_data *channel_hook_data;
00631     unsigned int channel_hook_count;
00632     ULONG extension_count;
00633     IPID ipid;
00634     HRESULT hr;
00635     APARTMENT *apt = NULL;
00636 
00637     TRACE("(%p)->(%p,%s)\n", This, olemsg, debugstr_guid(riid));
00638 
00639     cif = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RPC_CLIENT_INTERFACE));
00640     if (!cif)
00641         return E_OUTOFMEMORY;
00642 
00643     message_state = HeapAlloc(GetProcessHeap(), 0, sizeof(*message_state));
00644     if (!message_state)
00645     {
00646         HeapFree(GetProcessHeap(), 0, cif);
00647         return E_OUTOFMEMORY;
00648     }
00649 
00650     cif->Length = sizeof(RPC_CLIENT_INTERFACE);
00651     /* RPC interface ID = COM interface ID */
00652     cif->InterfaceId.SyntaxGUID = *riid;
00653     /* COM objects always have a version of 0.0 */
00654     cif->InterfaceId.SyntaxVersion.MajorVersion = 0;
00655     cif->InterfaceId.SyntaxVersion.MinorVersion = 0;
00656     msg->Handle = This->bind;
00657     msg->RpcInterfaceInformation = cif;
00658 
00659     message_state->prefix_data_len = 0;
00660     message_state->binding_handle = This->bind;
00661 
00662     message_state->channel_hook_info.iid = *riid;
00663     message_state->channel_hook_info.cbSize = sizeof(message_state->channel_hook_info);
00664     message_state->channel_hook_info.uCausality = COM_CurrentCausalityId();
00665     message_state->channel_hook_info.dwServerPid = This->server_pid;
00666     message_state->channel_hook_info.iMethod = msg->ProcNum;
00667     message_state->channel_hook_info.pObject = NULL; /* only present on server-side */
00668     message_state->target_hwnd = NULL;
00669     message_state->target_tid = 0;
00670     memset(&message_state->params, 0, sizeof(message_state->params));
00671 
00672     extensions_size = ChannelHooks_ClientGetSize(&message_state->channel_hook_info,
00673         &channel_hook_data, &channel_hook_count, &extension_count);
00674 
00675     msg->BufferLength += FIELD_OFFSET(WIRE_ORPCTHIS, extensions) + sizeof(DWORD);
00676     if (extensions_size)
00677     {
00678         msg->BufferLength += FIELD_OFFSET(WIRE_ORPC_EXTENT_ARRAY, extent[2*sizeof(DWORD) + extensions_size]);
00679         if (extension_count & 1)
00680             msg->BufferLength += FIELD_OFFSET(WIRE_ORPC_EXTENT, data[0]);
00681     }
00682 
00683     RpcBindingInqObject(message_state->binding_handle, &ipid);
00684     hr = ipid_get_dispatch_params(&ipid, &apt, &message_state->params.stub,
00685                                   &message_state->params.chan,
00686                                   &message_state->params.iid,
00687                                   &message_state->params.iface);
00688     if (hr == S_OK)
00689     {
00690         /* stub, chan, iface and iid are unneeded in multi-threaded case as we go
00691          * via the RPC runtime */
00692         if (apt->multi_threaded)
00693         {
00694             IRpcStubBuffer_Release(message_state->params.stub);
00695             message_state->params.stub = NULL;
00696             IRpcChannelBuffer_Release(message_state->params.chan);
00697             message_state->params.chan = NULL;
00698             message_state->params.iface = NULL;
00699         }
00700         else
00701         {
00702             message_state->params.bypass_rpcrt = TRUE;
00703             message_state->target_hwnd = apartment_getwindow(apt);
00704             message_state->target_tid = apt->tid;
00705             /* we assume later on that this being non-NULL is the indicator that
00706              * means call directly instead of going through RPC runtime */
00707             if (!message_state->target_hwnd)
00708                 ERR("window for apartment %s is NULL\n", wine_dbgstr_longlong(apt->oxid));
00709         }
00710     }
00711     if (apt) apartment_release(apt);
00712     message_state->params.handle = ClientRpcChannelBuffer_GetEventHandle(This);
00713     /* Note: message_state->params.msg is initialised in
00714      * ClientRpcChannelBuffer_SendReceive */
00715 
00716     /* shortcut the RPC runtime */
00717     if (message_state->target_hwnd)
00718     {
00719         msg->Buffer = HeapAlloc(GetProcessHeap(), 0, msg->BufferLength);
00720         if (msg->Buffer)
00721             status = RPC_S_OK;
00722         else
00723             status = ERROR_OUTOFMEMORY;
00724     }
00725     else
00726         status = I_RpcGetBuffer(msg);
00727 
00728     msg->Handle = message_state;
00729 
00730     if (status == RPC_S_OK)
00731     {
00732         orpcthis = msg->Buffer;
00733         msg->Buffer = (char *)msg->Buffer + FIELD_OFFSET(WIRE_ORPCTHIS, extensions);
00734 
00735         orpcthis->version.MajorVersion = COM_MAJOR_VERSION;
00736         orpcthis->version.MinorVersion = COM_MINOR_VERSION;
00737         orpcthis->flags = message_state->channel_hook_info.dwServerPid ? ORPCF_LOCAL : ORPCF_NULL;
00738         orpcthis->reserved1 = 0;
00739         orpcthis->cid = message_state->channel_hook_info.uCausality;
00740 
00741         /* NDR representation of orpcthis->extensions */
00742         *(DWORD *)msg->Buffer = extensions_size ? 1 : 0;
00743         msg->Buffer = (char *)msg->Buffer + sizeof(DWORD);
00744 
00745         if (extensions_size)
00746         {
00747             ORPC_EXTENT_ARRAY *orpc_extent_array = msg->Buffer;
00748             orpc_extent_array->size = extension_count;
00749             orpc_extent_array->reserved = 0;
00750             msg->Buffer = (char *)msg->Buffer + FIELD_OFFSET(WIRE_ORPC_EXTENT_ARRAY, extent);
00751             /* NDR representation of orpc_extent_array->extent */
00752             *(DWORD *)msg->Buffer = 1;
00753             msg->Buffer = (char *)msg->Buffer + sizeof(DWORD);
00754             /* NDR representation of [size_is] attribute of orpc_extent_array->extent */
00755             *(DWORD *)msg->Buffer = (extension_count + 1) & ~1;
00756             msg->Buffer = (char *)msg->Buffer + sizeof(DWORD);
00757 
00758             msg->Buffer = ChannelHooks_ClientFillBuffer(&message_state->channel_hook_info,
00759                 msg->Buffer, channel_hook_data, channel_hook_count);
00760 
00761             /* we must add a dummy extension if there is an odd extension
00762              * count to meet the contract specified by the size_is attribute */
00763             if (extension_count & 1)
00764             {
00765                 WIRE_ORPC_EXTENT *wire_orpc_extent = msg->Buffer;
00766                 wire_orpc_extent->conformance = 0;
00767                 wire_orpc_extent->id = GUID_NULL;
00768                 wire_orpc_extent->size = 0;
00769                 msg->Buffer = (char *)msg->Buffer + FIELD_OFFSET(WIRE_ORPC_EXTENT, data[0]);
00770             }
00771         }
00772 
00773         /* store the prefixed data length so that we can restore the real buffer
00774          * pointer in ClientRpcChannelBuffer_SendReceive. */
00775         message_state->prefix_data_len = (char *)msg->Buffer - (char *)orpcthis;
00776         msg->BufferLength -= message_state->prefix_data_len;
00777     }
00778 
00779     HeapFree(GetProcessHeap(), 0, channel_hook_data);
00780 
00781     TRACE("-- %d\n", status);
00782 
00783     return HRESULT_FROM_WIN32(status);
00784 }
00785 
00786 static HRESULT WINAPI ServerRpcChannelBuffer_SendReceive(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE *olemsg, ULONG *pstatus)
00787 {
00788     FIXME("stub\n");
00789     return E_NOTIMPL;
00790 }
00791 
00792 /* this thread runs an outgoing RPC */
00793 static DWORD WINAPI rpc_sendreceive_thread(LPVOID param)
00794 {
00795     struct dispatch_params *data = param;
00796 
00797     /* Note: I_RpcSendReceive doesn't raise exceptions like the higher-level
00798      * RPC functions do */
00799     data->status = I_RpcSendReceive((RPC_MESSAGE *)data->msg);
00800 
00801     TRACE("completed with status 0x%x\n", data->status);
00802 
00803     SetEvent(data->handle);
00804 
00805     return 0;
00806 }
00807 
00808 static inline HRESULT ClientRpcChannelBuffer_IsCorrectApartment(ClientRpcChannelBuffer *This, APARTMENT *apt)
00809 {
00810     OXID oxid;
00811     if (!apt)
00812         return S_FALSE;
00813     if (apartment_getoxid(apt, &oxid) != S_OK)
00814         return S_FALSE;
00815     if (This->oxid != oxid)
00816         return S_FALSE;
00817     return S_OK;
00818 }
00819 
00820 static HRESULT WINAPI ClientRpcChannelBuffer_SendReceive(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE *olemsg, ULONG *pstatus)
00821 {
00822     ClientRpcChannelBuffer *This = (ClientRpcChannelBuffer *)iface;
00823     HRESULT hr;
00824     RPC_MESSAGE *msg = (RPC_MESSAGE *)olemsg;
00825     RPC_STATUS status;
00826     DWORD index;
00827     struct message_state *message_state;
00828     ORPCTHAT orpcthat;
00829     ORPC_EXTENT_ARRAY orpc_ext_array;
00830     WIRE_ORPC_EXTENT *first_wire_orpc_extent = NULL;
00831     HRESULT hrFault = S_OK;
00832 
00833     TRACE("(%p) iMethod=%d\n", olemsg, olemsg->iMethod);
00834 
00835     hr = ClientRpcChannelBuffer_IsCorrectApartment(This, COM_CurrentApt());
00836     if (hr != S_OK)
00837     {
00838         ERR("called from wrong apartment, should have been 0x%s\n",
00839             wine_dbgstr_longlong(This->oxid));
00840         return RPC_E_WRONG_THREAD;
00841     }
00842     /* This situation should be impossible in multi-threaded apartments,
00843      * because the calling thread isn't re-enterable.
00844      * Note: doing a COM call during the processing of a sent message is
00845      * only disallowed if a client call is already being waited for
00846      * completion */
00847     if (!COM_CurrentApt()->multi_threaded &&
00848         COM_CurrentInfo()->pending_call_count_client &&
00849         InSendMessage())
00850     {
00851         ERR("can't make an outgoing COM call in response to a sent message\n");
00852         return RPC_E_CANTCALLOUT_ININPUTSYNCCALL;
00853     }
00854 
00855     message_state = msg->Handle;
00856     /* restore the binding handle and the real start of data */
00857     msg->Handle = message_state->binding_handle;
00858     msg->Buffer = (char *)msg->Buffer - message_state->prefix_data_len;
00859     msg->BufferLength += message_state->prefix_data_len;
00860 
00861     /* Note: this is an optimization in the Microsoft OLE runtime that we need
00862      * to copy, as shown by the test_no_couninitialize_client test. without
00863      * short-circuiting the RPC runtime in the case below, the test will
00864      * deadlock on the loader lock due to the RPC runtime needing to create
00865      * a thread to process the RPC when this function is called indirectly
00866      * from DllMain */
00867 
00868     message_state->params.msg = olemsg;
00869     if (message_state->params.bypass_rpcrt)
00870     {
00871         TRACE("Calling apartment thread 0x%08x...\n", message_state->target_tid);
00872 
00873         msg->ProcNum &= ~RPC_FLAGS_VALID_BIT;
00874 
00875         if (!PostMessageW(message_state->target_hwnd, DM_EXECUTERPC, 0,
00876                           (LPARAM)&message_state->params))
00877         {
00878             ERR("PostMessage failed with error %u\n", GetLastError());
00879 
00880             /* Note: message_state->params.iface doesn't have a reference and
00881              * so doesn't need to be released */
00882 
00883             hr = HRESULT_FROM_WIN32(GetLastError());
00884         }
00885     }
00886     else
00887     {
00888         /* we use a separate thread here because we need to be able to
00889          * pump the message loop in the application thread: if we do not,
00890          * any windows created by this thread will hang and RPCs that try
00891          * and re-enter this STA from an incoming server thread will
00892          * deadlock. InstallShield is an example of that.
00893          */
00894         if (!QueueUserWorkItem(rpc_sendreceive_thread, &message_state->params, WT_EXECUTEDEFAULT))
00895         {
00896             ERR("QueueUserWorkItem failed with error %u\n", GetLastError());
00897             hr = E_UNEXPECTED;
00898         }
00899         else
00900             hr = S_OK;
00901     }
00902 
00903     if (hr == S_OK)
00904     {
00905         if (WaitForSingleObject(message_state->params.handle, 0))
00906         {
00907             COM_CurrentInfo()->pending_call_count_client++;
00908             hr = CoWaitForMultipleHandles(0, INFINITE, 1, &message_state->params.handle, &index);
00909             COM_CurrentInfo()->pending_call_count_client--;
00910         }
00911     }
00912     ClientRpcChannelBuffer_ReleaseEventHandle(This, message_state->params.handle);
00913 
00914     /* for WM shortcut, faults are returned in params->hr */
00915     if (hr == S_OK)
00916         hrFault = message_state->params.hr;
00917 
00918     status = message_state->params.status;
00919 
00920     orpcthat.flags = ORPCF_NULL;
00921     orpcthat.extensions = NULL;
00922 
00923     TRACE("RPC call status: 0x%x\n", status);
00924     if (status != RPC_S_OK)
00925         hr = HRESULT_FROM_WIN32(status);
00926 
00927     TRACE("hrFault = 0x%08x\n", hrFault);
00928 
00929     /* FIXME: this condition should be
00930      * "hr == S_OK && (!hrFault || msg->BufferLength > FIELD_OFFSET(ORPCTHAT, extensions) + 4)"
00931      * but we don't currently reset the message length for PostMessage
00932      * dispatched calls */
00933     if (hr == S_OK && hrFault == S_OK)
00934     {
00935         HRESULT hr2;
00936         char *original_buffer = msg->Buffer;
00937 
00938         /* handle ORPCTHAT and client extensions */
00939 
00940         hr2 = unmarshal_ORPCTHAT(msg, &orpcthat, &orpc_ext_array, &first_wire_orpc_extent);
00941         if (FAILED(hr2))
00942             hr = hr2;
00943 
00944         message_state->prefix_data_len = (char *)msg->Buffer - original_buffer;
00945         msg->BufferLength -= message_state->prefix_data_len;
00946     }
00947     else
00948         message_state->prefix_data_len = 0;
00949 
00950     if (hr == S_OK)
00951     {
00952         ChannelHooks_ClientNotify(&message_state->channel_hook_info,
00953                                   msg->DataRepresentation,
00954                                   first_wire_orpc_extent,
00955                                   orpcthat.extensions && first_wire_orpc_extent ? orpcthat.extensions->size : 0,
00956                                   hrFault);
00957     }
00958 
00959     /* save away the message state again */
00960     msg->Handle = message_state;
00961 
00962     if (pstatus) *pstatus = status;
00963 
00964     if (hr == S_OK)
00965         hr = hrFault;
00966 
00967     TRACE("-- 0x%08x\n", hr);
00968 
00969     return hr;
00970 }
00971 
00972 static HRESULT WINAPI ServerRpcChannelBuffer_FreeBuffer(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE* olemsg)
00973 {
00974     RPC_MESSAGE *msg = (RPC_MESSAGE *)olemsg;
00975     RPC_STATUS status;
00976     struct message_state *message_state;
00977 
00978     TRACE("(%p)\n", msg);
00979 
00980     message_state = msg->Handle;
00981     /* restore the binding handle and the real start of data */
00982     msg->Handle = message_state->binding_handle;
00983     msg->Buffer = (char *)msg->Buffer - message_state->prefix_data_len;
00984     msg->BufferLength += message_state->prefix_data_len;
00985     message_state->prefix_data_len = 0;
00986 
00987     if (message_state->bypass_rpcrt)
00988     {
00989         HeapFree(GetProcessHeap(), 0, msg->Buffer);
00990         status = RPC_S_OK;
00991     }
00992     else
00993         status = I_RpcFreeBuffer(msg);
00994 
00995     msg->Handle = message_state;
00996 
00997     TRACE("-- %d\n", status);
00998 
00999     return HRESULT_FROM_WIN32(status);
01000 }
01001 
01002 static HRESULT WINAPI ClientRpcChannelBuffer_FreeBuffer(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE* olemsg)
01003 {
01004     RPC_MESSAGE *msg = (RPC_MESSAGE *)olemsg;
01005     RPC_STATUS status;
01006     struct message_state *message_state;
01007 
01008     TRACE("(%p)\n", msg);
01009 
01010     message_state = msg->Handle;
01011     /* restore the binding handle and the real start of data */
01012     msg->Handle = message_state->binding_handle;
01013     msg->Buffer = (char *)msg->Buffer - message_state->prefix_data_len;
01014     msg->BufferLength += message_state->prefix_data_len;
01015 
01016     if (message_state->params.bypass_rpcrt)
01017     {
01018         HeapFree(GetProcessHeap(), 0, msg->Buffer);
01019         status = RPC_S_OK;
01020     }
01021     else
01022         status = I_RpcFreeBuffer(msg);
01023 
01024     HeapFree(GetProcessHeap(), 0, msg->RpcInterfaceInformation);
01025     msg->RpcInterfaceInformation = NULL;
01026 
01027     if (message_state->params.stub)
01028         IRpcStubBuffer_Release(message_state->params.stub);
01029     if (message_state->params.chan)
01030         IRpcChannelBuffer_Release(message_state->params.chan);
01031     HeapFree(GetProcessHeap(), 0, message_state);
01032 
01033     TRACE("-- %d\n", status);
01034 
01035     return HRESULT_FROM_WIN32(status);
01036 }
01037 
01038 static HRESULT WINAPI ClientRpcChannelBuffer_GetDestCtx(LPRPCCHANNELBUFFER iface, DWORD* pdwDestContext, void** ppvDestContext)
01039 {
01040     ClientRpcChannelBuffer *This = (ClientRpcChannelBuffer *)iface;
01041 
01042     TRACE("(%p,%p)\n", pdwDestContext, ppvDestContext);
01043 
01044     *pdwDestContext = This->dest_context;
01045     *ppvDestContext = This->dest_context_data;
01046 
01047     return S_OK;
01048 }
01049 
01050 static HRESULT WINAPI ServerRpcChannelBuffer_GetDestCtx(LPRPCCHANNELBUFFER iface, DWORD* pdwDestContext, void** ppvDestContext)
01051 {
01052     WARN("(%p,%p), stub!\n", pdwDestContext, ppvDestContext);
01053 
01054     /* FIXME: implement this by storing the dwDestContext and pvDestContext
01055      * values passed into IMarshal_MarshalInterface and returning them here */
01056     *pdwDestContext = MSHCTX_DIFFERENTMACHINE;
01057     *ppvDestContext = NULL;
01058     return S_OK;
01059 }
01060 
01061 static HRESULT WINAPI RpcChannelBuffer_IsConnected(LPRPCCHANNELBUFFER iface)
01062 {
01063     TRACE("()\n");
01064     /* native does nothing too */
01065     return S_OK;
01066 }
01067 
01068 static const IRpcChannelBufferVtbl ClientRpcChannelBufferVtbl =
01069 {
01070     RpcChannelBuffer_QueryInterface,
01071     RpcChannelBuffer_AddRef,
01072     ClientRpcChannelBuffer_Release,
01073     ClientRpcChannelBuffer_GetBuffer,
01074     ClientRpcChannelBuffer_SendReceive,
01075     ClientRpcChannelBuffer_FreeBuffer,
01076     ClientRpcChannelBuffer_GetDestCtx,
01077     RpcChannelBuffer_IsConnected
01078 };
01079 
01080 static const IRpcChannelBufferVtbl ServerRpcChannelBufferVtbl =
01081 {
01082     RpcChannelBuffer_QueryInterface,
01083     RpcChannelBuffer_AddRef,
01084     ServerRpcChannelBuffer_Release,
01085     ServerRpcChannelBuffer_GetBuffer,
01086     ServerRpcChannelBuffer_SendReceive,
01087     ServerRpcChannelBuffer_FreeBuffer,
01088     ServerRpcChannelBuffer_GetDestCtx,
01089     RpcChannelBuffer_IsConnected
01090 };
01091 
01092 /* returns a channel buffer for proxies */
01093 HRESULT RPC_CreateClientChannel(const OXID *oxid, const IPID *ipid,
01094                                 const OXID_INFO *oxid_info,
01095                                 DWORD dest_context, void *dest_context_data,
01096                                 IRpcChannelBuffer **chan)
01097 {
01098     ClientRpcChannelBuffer *This;
01099     WCHAR                   endpoint[200];
01100     RPC_BINDING_HANDLE      bind;
01101     RPC_STATUS              status;
01102     LPWSTR                  string_binding;
01103 
01104     /* FIXME: get the endpoint from oxid_info->psa instead */
01105     get_rpc_endpoint(endpoint, oxid);
01106 
01107     TRACE("proxy pipe: connecting to endpoint: %s\n", debugstr_w(endpoint));
01108 
01109     status = RpcStringBindingComposeW(
01110         NULL,
01111         wszRpcTransport,
01112         NULL,
01113         endpoint,
01114         NULL,
01115         &string_binding);
01116         
01117     if (status == RPC_S_OK)
01118     {
01119         status = RpcBindingFromStringBindingW(string_binding, &bind);
01120 
01121         if (status == RPC_S_OK)
01122         {
01123             IPID ipid2 = *ipid; /* why can't RpcBindingSetObject take a const? */
01124             status = RpcBindingSetObject(bind, &ipid2);
01125             if (status != RPC_S_OK)
01126                 RpcBindingFree(&bind);
01127         }
01128 
01129         RpcStringFreeW(&string_binding);
01130     }
01131 
01132     if (status != RPC_S_OK)
01133     {
01134         ERR("Couldn't get binding for endpoint %s, status = %d\n", debugstr_w(endpoint), status);
01135         return HRESULT_FROM_WIN32(status);
01136     }
01137 
01138     This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
01139     if (!This)
01140     {
01141         RpcBindingFree(&bind);
01142         return E_OUTOFMEMORY;
01143     }
01144 
01145     This->super.lpVtbl = &ClientRpcChannelBufferVtbl;
01146     This->super.refs = 1;
01147     This->bind = bind;
01148     apartment_getoxid(COM_CurrentApt(), &This->oxid);
01149     This->server_pid = oxid_info->dwPid;
01150     This->dest_context = dest_context;
01151     This->dest_context_data = dest_context_data;
01152     This->event = NULL;
01153 
01154     *chan = (IRpcChannelBuffer*)This;
01155 
01156     return S_OK;
01157 }
01158 
01159 HRESULT RPC_CreateServerChannel(IRpcChannelBuffer **chan)
01160 {
01161     RpcChannelBuffer *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
01162     if (!This)
01163         return E_OUTOFMEMORY;
01164 
01165     This->lpVtbl = &ServerRpcChannelBufferVtbl;
01166     This->refs = 1;
01167     
01168     *chan = (IRpcChannelBuffer*)This;
01169 
01170     return S_OK;
01171 }
01172 
01173 /* unmarshals ORPC_EXTENT_ARRAY according to NDR rules, but doesn't allocate
01174  * any memory */
01175 static HRESULT unmarshal_ORPC_EXTENT_ARRAY(RPC_MESSAGE *msg, const char *end,
01176                                            ORPC_EXTENT_ARRAY *extensions,
01177                                            WIRE_ORPC_EXTENT **first_wire_orpc_extent)
01178 {
01179     DWORD pointer_id;
01180     DWORD i;
01181 
01182     memcpy(extensions, msg->Buffer, FIELD_OFFSET(WIRE_ORPC_EXTENT_ARRAY, extent));
01183     msg->Buffer = (char *)msg->Buffer + FIELD_OFFSET(WIRE_ORPC_EXTENT_ARRAY, extent);
01184 
01185     if ((const char *)msg->Buffer + 2 * sizeof(DWORD) > end)
01186         return RPC_E_INVALID_HEADER;
01187 
01188     pointer_id = *(DWORD *)msg->Buffer;
01189     msg->Buffer = (char *)msg->Buffer + sizeof(DWORD);
01190     extensions->extent = NULL;
01191 
01192     if (pointer_id)
01193     {
01194         WIRE_ORPC_EXTENT *wire_orpc_extent;
01195 
01196         /* conformance */
01197         if (*(DWORD *)msg->Buffer != ((extensions->size+1)&~1))
01198             return RPC_S_INVALID_BOUND;
01199 
01200         msg->Buffer = (char *)msg->Buffer + sizeof(DWORD);
01201 
01202         /* arbitrary limit for security (don't know what native does) */
01203         if (extensions->size > 256)
01204         {
01205             ERR("too many extensions: %d\n", extensions->size);
01206             return RPC_S_INVALID_BOUND;
01207         }
01208 
01209         *first_wire_orpc_extent = wire_orpc_extent = msg->Buffer;
01210         for (i = 0; i < ((extensions->size+1)&~1); i++)
01211         {
01212             if ((const char *)&wire_orpc_extent->data[0] > end)
01213                 return RPC_S_INVALID_BOUND;
01214             if (wire_orpc_extent->conformance != ((wire_orpc_extent->size+7)&~7))
01215                 return RPC_S_INVALID_BOUND;
01216             if ((const char *)&wire_orpc_extent->data[wire_orpc_extent->conformance] > end)
01217                 return RPC_S_INVALID_BOUND;
01218             TRACE("size %u, guid %s\n", wire_orpc_extent->size, debugstr_guid(&wire_orpc_extent->id));
01219             wire_orpc_extent = (WIRE_ORPC_EXTENT *)&wire_orpc_extent->data[wire_orpc_extent->conformance];
01220         }
01221         msg->Buffer = wire_orpc_extent;
01222     }
01223 
01224     return S_OK;
01225 }
01226 
01227 /* unmarshals ORPCTHIS according to NDR rules, but doesn't allocate any memory */
01228 static HRESULT unmarshal_ORPCTHIS(RPC_MESSAGE *msg, ORPCTHIS *orpcthis,
01229     ORPC_EXTENT_ARRAY *orpc_ext_array, WIRE_ORPC_EXTENT **first_wire_orpc_extent)
01230 {
01231     const char *end = (char *)msg->Buffer + msg->BufferLength;
01232 
01233     *first_wire_orpc_extent = NULL;
01234 
01235     if (msg->BufferLength < FIELD_OFFSET(WIRE_ORPCTHIS, extensions) + sizeof(DWORD))
01236     {
01237         ERR("invalid buffer length\n");
01238         return RPC_E_INVALID_HEADER;
01239     }
01240 
01241     memcpy(orpcthis, msg->Buffer, FIELD_OFFSET(WIRE_ORPCTHIS, extensions));
01242     msg->Buffer = (char *)msg->Buffer + FIELD_OFFSET(WIRE_ORPCTHIS, extensions);
01243 
01244     if ((const char *)msg->Buffer + sizeof(DWORD) > end)
01245         return RPC_E_INVALID_HEADER;
01246 
01247     if (*(DWORD *)msg->Buffer)
01248         orpcthis->extensions = orpc_ext_array;
01249     else
01250         orpcthis->extensions = NULL;
01251 
01252     msg->Buffer = (char *)msg->Buffer + sizeof(DWORD);
01253 
01254     if (orpcthis->extensions)
01255     {
01256         HRESULT hr = unmarshal_ORPC_EXTENT_ARRAY(msg, end, orpc_ext_array,
01257                                                  first_wire_orpc_extent);
01258         if (FAILED(hr))
01259             return hr;
01260     }
01261 
01262     if ((orpcthis->version.MajorVersion != COM_MAJOR_VERSION) ||
01263         (orpcthis->version.MinorVersion > COM_MINOR_VERSION))
01264     {
01265         ERR("COM version {%d, %d} not supported\n",
01266             orpcthis->version.MajorVersion, orpcthis->version.MinorVersion);
01267         return RPC_E_VERSION_MISMATCH;
01268     }
01269 
01270     if (orpcthis->flags & ~(ORPCF_LOCAL|ORPCF_RESERVED1|ORPCF_RESERVED2|ORPCF_RESERVED3|ORPCF_RESERVED4))
01271     {
01272         ERR("invalid flags 0x%x\n", orpcthis->flags & ~(ORPCF_LOCAL|ORPCF_RESERVED1|ORPCF_RESERVED2|ORPCF_RESERVED3|ORPCF_RESERVED4));
01273         return RPC_E_INVALID_HEADER;
01274     }
01275 
01276     return S_OK;
01277 }
01278 
01279 static HRESULT unmarshal_ORPCTHAT(RPC_MESSAGE *msg, ORPCTHAT *orpcthat,
01280                                   ORPC_EXTENT_ARRAY *orpc_ext_array, WIRE_ORPC_EXTENT **first_wire_orpc_extent)
01281 {
01282     const char *end = (char *)msg->Buffer + msg->BufferLength;
01283 
01284     *first_wire_orpc_extent = NULL;
01285 
01286     if (msg->BufferLength < FIELD_OFFSET(WIRE_ORPCTHAT, extensions) + sizeof(DWORD))
01287     {
01288         ERR("invalid buffer length\n");
01289         return RPC_E_INVALID_HEADER;
01290     }
01291 
01292     memcpy(orpcthat, msg->Buffer, FIELD_OFFSET(WIRE_ORPCTHAT, extensions));
01293     msg->Buffer = (char *)msg->Buffer + FIELD_OFFSET(WIRE_ORPCTHAT, extensions);
01294 
01295     if ((const char *)msg->Buffer + sizeof(DWORD) > end)
01296         return RPC_E_INVALID_HEADER;
01297 
01298     if (*(DWORD *)msg->Buffer)
01299         orpcthat->extensions = orpc_ext_array;
01300     else
01301         orpcthat->extensions = NULL;
01302 
01303     msg->Buffer = (char *)msg->Buffer + sizeof(DWORD);
01304 
01305     if (orpcthat->extensions)
01306     {
01307         HRESULT hr = unmarshal_ORPC_EXTENT_ARRAY(msg, end, orpc_ext_array,
01308                                                  first_wire_orpc_extent);
01309         if (FAILED(hr))
01310             return hr;
01311     }
01312 
01313     if (orpcthat->flags & ~(ORPCF_LOCAL|ORPCF_RESERVED1|ORPCF_RESERVED2|ORPCF_RESERVED3|ORPCF_RESERVED4))
01314     {
01315         ERR("invalid flags 0x%x\n", orpcthat->flags & ~(ORPCF_LOCAL|ORPCF_RESERVED1|ORPCF_RESERVED2|ORPCF_RESERVED3|ORPCF_RESERVED4));
01316         return RPC_E_INVALID_HEADER;
01317     }
01318 
01319     return S_OK;
01320 }
01321 
01322 void RPC_ExecuteCall(struct dispatch_params *params)
01323 {
01324     struct message_state *message_state = NULL;
01325     RPC_MESSAGE *msg = (RPC_MESSAGE *)params->msg;
01326     char *original_buffer = msg->Buffer;
01327     ORPCTHIS orpcthis;
01328     ORPC_EXTENT_ARRAY orpc_ext_array;
01329     WIRE_ORPC_EXTENT *first_wire_orpc_extent;
01330     GUID old_causality_id;
01331 
01332     /* handle ORPCTHIS and server extensions */
01333 
01334     params->hr = unmarshal_ORPCTHIS(msg, &orpcthis, &orpc_ext_array, &first_wire_orpc_extent);
01335     if (params->hr != S_OK)
01336     {
01337         msg->Buffer = original_buffer;
01338         goto exit;
01339     }
01340 
01341     message_state = HeapAlloc(GetProcessHeap(), 0, sizeof(*message_state));
01342     if (!message_state)
01343     {
01344         params->hr = E_OUTOFMEMORY;
01345         msg->Buffer = original_buffer;
01346         goto exit;
01347     }
01348 
01349     message_state->prefix_data_len = (char *)msg->Buffer - original_buffer;
01350     message_state->binding_handle = msg->Handle;
01351     message_state->bypass_rpcrt = params->bypass_rpcrt;
01352 
01353     message_state->channel_hook_info.iid = params->iid;
01354     message_state->channel_hook_info.cbSize = sizeof(message_state->channel_hook_info);
01355     message_state->channel_hook_info.uCausality = orpcthis.cid;
01356     message_state->channel_hook_info.dwServerPid = GetCurrentProcessId();
01357     message_state->channel_hook_info.iMethod = msg->ProcNum;
01358     message_state->channel_hook_info.pObject = params->iface;
01359 
01360     if (orpcthis.extensions && first_wire_orpc_extent &&
01361         orpcthis.extensions->size)
01362         ChannelHooks_ServerNotify(&message_state->channel_hook_info, msg->DataRepresentation, first_wire_orpc_extent, orpcthis.extensions->size);
01363 
01364     msg->Handle = message_state;
01365     msg->BufferLength -= message_state->prefix_data_len;
01366 
01367     /* call message filter */
01368 
01369     if (COM_CurrentApt()->filter)
01370     {
01371         DWORD handlecall;
01372         INTERFACEINFO interface_info;
01373         CALLTYPE calltype;
01374 
01375         interface_info.pUnk = params->iface;
01376         interface_info.iid = params->iid;
01377         interface_info.wMethod = msg->ProcNum;
01378 
01379         if (IsEqualGUID(&orpcthis.cid, &COM_CurrentInfo()->causality_id))
01380             calltype = CALLTYPE_NESTED;
01381         else if (COM_CurrentInfo()->pending_call_count_server == 0)
01382             calltype = CALLTYPE_TOPLEVEL;
01383         else
01384             calltype = CALLTYPE_TOPLEVEL_CALLPENDING;
01385 
01386         handlecall = IMessageFilter_HandleInComingCall(COM_CurrentApt()->filter,
01387                                                        calltype,
01388                                                        UlongToHandle(GetCurrentProcessId()),
01389                                                        0 /* FIXME */,
01390                                                        &interface_info);
01391         TRACE("IMessageFilter_HandleInComingCall returned %d\n", handlecall);
01392         switch (handlecall)
01393         {
01394         case SERVERCALL_REJECTED:
01395             params->hr = RPC_E_CALL_REJECTED;
01396             goto exit_reset_state;
01397         case SERVERCALL_RETRYLATER:
01398 #if 0 /* FIXME: handle retries on the client side before enabling this code */
01399             params->hr = RPC_E_RETRY;
01400             goto exit_reset_state;
01401 #else
01402             FIXME("retry call later not implemented\n");
01403             break;
01404 #endif
01405         case SERVERCALL_ISHANDLED:
01406         default:
01407             break;
01408         }
01409     }
01410 
01411     /* invoke the method */
01412 
01413     /* save the old causality ID - note: any calls executed while processing
01414      * messages received during the SendReceive will appear to originate from
01415      * this call - this should be checked with what Windows does */
01416     old_causality_id = COM_CurrentInfo()->causality_id;
01417     COM_CurrentInfo()->causality_id = orpcthis.cid;
01418     COM_CurrentInfo()->pending_call_count_server++;
01419     params->hr = IRpcStubBuffer_Invoke(params->stub, params->msg, params->chan);
01420     COM_CurrentInfo()->pending_call_count_server--;
01421     COM_CurrentInfo()->causality_id = old_causality_id;
01422 
01423     /* the invoke allocated a new buffer, so free the old one */
01424     if (message_state->bypass_rpcrt && original_buffer != msg->Buffer)
01425         HeapFree(GetProcessHeap(), 0, original_buffer);
01426 
01427 exit_reset_state:
01428     message_state = msg->Handle;
01429     msg->Handle = message_state->binding_handle;
01430     msg->Buffer = (char *)msg->Buffer - message_state->prefix_data_len;
01431     msg->BufferLength += message_state->prefix_data_len;
01432 
01433 exit:
01434     HeapFree(GetProcessHeap(), 0, message_state);
01435     if (params->handle) SetEvent(params->handle);
01436 }
01437 
01438 static void __RPC_STUB dispatch_rpc(RPC_MESSAGE *msg)
01439 {
01440     struct dispatch_params *params;
01441     APARTMENT *apt;
01442     IPID ipid;
01443     HRESULT hr;
01444 
01445     RpcBindingInqObject(msg->Handle, &ipid);
01446 
01447     TRACE("ipid = %s, iMethod = %d\n", debugstr_guid(&ipid), msg->ProcNum);
01448 
01449     params = HeapAlloc(GetProcessHeap(), 0, sizeof(*params));
01450     if (!params)
01451     {
01452         RpcRaiseException(E_OUTOFMEMORY);
01453         return;
01454     }
01455 
01456     hr = ipid_get_dispatch_params(&ipid, &apt, &params->stub, &params->chan,
01457                                   &params->iid, &params->iface);
01458     if (hr != S_OK)
01459     {
01460         ERR("no apartment found for ipid %s\n", debugstr_guid(&ipid));
01461         HeapFree(GetProcessHeap(), 0, params);
01462         RpcRaiseException(hr);
01463         return;
01464     }
01465 
01466     params->msg = (RPCOLEMESSAGE *)msg;
01467     params->status = RPC_S_OK;
01468     params->hr = S_OK;
01469     params->handle = NULL;
01470     params->bypass_rpcrt = FALSE;
01471 
01472     /* Note: this is the important difference between STAs and MTAs - we
01473      * always execute RPCs to STAs in the thread that originally created the
01474      * apartment (i.e. the one that pumps messages to the window) */
01475     if (!apt->multi_threaded)
01476     {
01477         params->handle = CreateEventW(NULL, FALSE, FALSE, NULL);
01478 
01479         TRACE("Calling apartment thread 0x%08x...\n", apt->tid);
01480 
01481         if (PostMessageW(apartment_getwindow(apt), DM_EXECUTERPC, 0, (LPARAM)params))
01482             WaitForSingleObject(params->handle, INFINITE);
01483         else
01484         {
01485             ERR("PostMessage failed with error %u\n", GetLastError());
01486             IRpcChannelBuffer_Release(params->chan);
01487             IRpcStubBuffer_Release(params->stub);
01488         }
01489         CloseHandle(params->handle);
01490     }
01491     else
01492     {
01493         BOOL joined = FALSE;
01494         if (!COM_CurrentInfo()->apt)
01495         {
01496             apartment_joinmta();
01497             joined = TRUE;
01498         }
01499         RPC_ExecuteCall(params);
01500         if (joined)
01501         {
01502             apartment_release(COM_CurrentInfo()->apt);
01503             COM_CurrentInfo()->apt = NULL;
01504         }
01505     }
01506 
01507     hr = params->hr;
01508     if (params->chan)
01509         IRpcChannelBuffer_Release(params->chan);
01510     if (params->stub)
01511         IRpcStubBuffer_Release(params->stub);
01512     HeapFree(GetProcessHeap(), 0, params);
01513 
01514     apartment_release(apt);
01515 
01516     /* if IRpcStubBuffer_Invoke fails, we should raise an exception to tell
01517      * the RPC runtime that the call failed */
01518     if (hr) RpcRaiseException(hr);
01519 }
01520 
01521 /* stub registration */
01522 HRESULT RPC_RegisterInterface(REFIID riid)
01523 {
01524     struct registered_if *rif;
01525     BOOL found = FALSE;
01526     HRESULT hr = S_OK;
01527     
01528     TRACE("(%s)\n", debugstr_guid(riid));
01529 
01530     EnterCriticalSection(&csRegIf);
01531     LIST_FOR_EACH_ENTRY(rif, &registered_interfaces, struct registered_if, entry)
01532     {
01533         if (IsEqualGUID(&rif->If.InterfaceId.SyntaxGUID, riid))
01534         {
01535             rif->refs++;
01536             found = TRUE;
01537             break;
01538         }
01539     }
01540     if (!found)
01541     {
01542         TRACE("Creating new interface\n");
01543 
01544         rif = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*rif));
01545         if (rif)
01546         {
01547             RPC_STATUS status;
01548 
01549             rif->refs = 1;
01550             rif->If.Length = sizeof(RPC_SERVER_INTERFACE);
01551             /* RPC interface ID = COM interface ID */
01552             rif->If.InterfaceId.SyntaxGUID = *riid;
01553             rif->If.DispatchTable = &rpc_dispatch;
01554             /* all other fields are 0, including the version asCOM objects
01555              * always have a version of 0.0 */
01556             status = RpcServerRegisterIfEx(
01557                 (RPC_IF_HANDLE)&rif->If,
01558                 NULL, NULL,
01559                 RPC_IF_OLE | RPC_IF_AUTOLISTEN,
01560                 RPC_C_LISTEN_MAX_CALLS_DEFAULT,
01561                 NULL);
01562             if (status == RPC_S_OK)
01563                 list_add_tail(&registered_interfaces, &rif->entry);
01564             else
01565             {
01566                 ERR("RpcServerRegisterIfEx failed with error %d\n", status);
01567                 HeapFree(GetProcessHeap(), 0, rif);
01568                 hr = HRESULT_FROM_WIN32(status);
01569             }
01570         }
01571         else
01572             hr = E_OUTOFMEMORY;
01573     }
01574     LeaveCriticalSection(&csRegIf);
01575     return hr;
01576 }
01577 
01578 /* stub unregistration */
01579 void RPC_UnregisterInterface(REFIID riid)
01580 {
01581     struct registered_if *rif;
01582     EnterCriticalSection(&csRegIf);
01583     LIST_FOR_EACH_ENTRY(rif, &registered_interfaces, struct registered_if, entry)
01584     {
01585         if (IsEqualGUID(&rif->If.InterfaceId.SyntaxGUID, riid))
01586         {
01587             if (!--rif->refs)
01588             {
01589                 RpcServerUnregisterIf((RPC_IF_HANDLE)&rif->If, NULL, TRUE);
01590                 list_remove(&rif->entry);
01591                 HeapFree(GetProcessHeap(), 0, rif);
01592             }
01593             break;
01594         }
01595     }
01596     LeaveCriticalSection(&csRegIf);
01597 }
01598 
01599 /* get the info for an OXID, including the IPID for the rem unknown interface
01600  * and the string binding */
01601 HRESULT RPC_ResolveOxid(OXID oxid, OXID_INFO *oxid_info)
01602 {
01603     TRACE("%s\n", wine_dbgstr_longlong(oxid));
01604 
01605     oxid_info->dwTid = 0;
01606     oxid_info->dwPid = 0;
01607     oxid_info->dwAuthnHint = RPC_C_AUTHN_LEVEL_NONE;
01608     /* FIXME: this is a hack around not having an OXID resolver yet -
01609      * this function should contact the machine's OXID resolver and then it
01610      * should give us the IPID of the IRemUnknown interface */
01611     oxid_info->ipidRemUnknown.Data1 = 0xffffffff;
01612     oxid_info->ipidRemUnknown.Data2 = 0xffff;
01613     oxid_info->ipidRemUnknown.Data3 = 0xffff;
01614     memcpy(oxid_info->ipidRemUnknown.Data4, &oxid, sizeof(OXID));
01615     oxid_info->psa = NULL /* FIXME */;
01616 
01617     return S_OK;
01618 }
01619 
01620 /* make the apartment reachable by other threads and processes and create the
01621  * IRemUnknown object */
01622 void RPC_StartRemoting(struct apartment *apt)
01623 {
01624     if (!InterlockedExchange(&apt->remoting_started, TRUE))
01625     {
01626         WCHAR endpoint[200];
01627         RPC_STATUS status;
01628 
01629         get_rpc_endpoint(endpoint, &apt->oxid);
01630     
01631         status = RpcServerUseProtseqEpW(
01632             wszRpcTransport,
01633             RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
01634             endpoint,
01635             NULL);
01636         if (status != RPC_S_OK)
01637             ERR("Couldn't register endpoint %s\n", debugstr_w(endpoint));
01638 
01639         /* FIXME: move remote unknown exporting into this function */
01640     }
01641     start_apartment_remote_unknown();
01642 }
01643 
01644 
01645 static HRESULT create_server(REFCLSID rclsid, HANDLE *process)
01646 {
01647     static const WCHAR  wszLocalServer32[] = { 'L','o','c','a','l','S','e','r','v','e','r','3','2',0 };
01648     static const WCHAR  embedding[] = { ' ', '-','E','m','b','e','d','d','i','n','g',0 };
01649     HKEY                key;
01650     HRESULT             hres;
01651     WCHAR               command[MAX_PATH+sizeof(embedding)/sizeof(WCHAR)];
01652     DWORD               size = (MAX_PATH+1) * sizeof(WCHAR);
01653     STARTUPINFOW        sinfo;
01654     PROCESS_INFORMATION pinfo;
01655 
01656     hres = COM_OpenKeyForCLSID(rclsid, wszLocalServer32, KEY_READ, &key);
01657     if (FAILED(hres)) {
01658         ERR("class %s not registered\n", debugstr_guid(rclsid));
01659         return hres;
01660     }
01661 
01662     hres = RegQueryValueExW(key, NULL, NULL, NULL, (LPBYTE)command, &size);
01663     RegCloseKey(key);
01664     if (hres) {
01665         WARN("No default value for LocalServer32 key\n");
01666         return REGDB_E_CLASSNOTREG; /* FIXME: check retval */
01667     }
01668 
01669     memset(&sinfo,0,sizeof(sinfo));
01670     sinfo.cb = sizeof(sinfo);
01671 
01672     /* EXE servers are started with the -Embedding switch. */
01673 
01674     strcatW(command, embedding);
01675 
01676     TRACE("activating local server %s for %s\n", debugstr_w(command), debugstr_guid(rclsid));
01677 
01678     /* FIXME: Win2003 supports a ServerExecutable value that is passed into
01679      * CreateProcess */
01680     if (!CreateProcessW(NULL, command, NULL, NULL, FALSE, 0, NULL, NULL, &sinfo, &pinfo)) {
01681         WARN("failed to run local server %s\n", debugstr_w(command));
01682         return HRESULT_FROM_WIN32(GetLastError());
01683     }
01684     *process = pinfo.hProcess;
01685     CloseHandle(pinfo.hThread);
01686 
01687     return S_OK;
01688 }
01689 
01690 /*
01691  * start_local_service()  - start a service given its name and parameters
01692  */
01693 static DWORD start_local_service(LPCWSTR name, DWORD num, LPCWSTR *params)
01694 {
01695     SC_HANDLE handle, hsvc;
01696     DWORD     r = ERROR_FUNCTION_FAILED;
01697 
01698     TRACE("Starting service %s %d params\n", debugstr_w(name), num);
01699 
01700     handle = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
01701     if (!handle)
01702         return r;
01703     hsvc = OpenServiceW(handle, name, SERVICE_START);
01704     if (hsvc)
01705     {
01706         if(StartServiceW(hsvc, num, params))
01707             r = ERROR_SUCCESS;
01708         else
01709             r = GetLastError();
01710         if (r == ERROR_SERVICE_ALREADY_RUNNING)
01711             r = ERROR_SUCCESS;
01712         CloseServiceHandle(hsvc);
01713     }
01714     else
01715         r = GetLastError();
01716     CloseServiceHandle(handle);
01717 
01718     TRACE("StartService returned error %u (%s)\n", r, (r == ERROR_SUCCESS) ? "ok":"failed");
01719 
01720     return r;
01721 }
01722 
01723 /*
01724  * create_local_service()  - start a COM server in a service
01725  *
01726  *   To start a Local Service, we read the AppID value under
01727  * the class's CLSID key, then open the HKCR\\AppId key specified
01728  * there and check for a LocalService value.
01729  *
01730  * Note:  Local Services are not supported under Windows 9x
01731  */
01732 static HRESULT create_local_service(REFCLSID rclsid)
01733 {
01734     HRESULT hres;
01735     WCHAR buf[CHARS_IN_GUID];
01736     static const WCHAR szLocalService[] = { 'L','o','c','a','l','S','e','r','v','i','c','e',0 };
01737     static const WCHAR szServiceParams[] = {'S','e','r','v','i','c','e','P','a','r','a','m','s',0};
01738     HKEY hkey;
01739     LONG r;
01740     DWORD type, sz;
01741 
01742     TRACE("Attempting to start Local service for %s\n", debugstr_guid(rclsid));
01743 
01744     hres = COM_OpenKeyForAppIdFromCLSID(rclsid, KEY_READ, &hkey);
01745     if (FAILED(hres))
01746         return hres;
01747 
01748     /* read the LocalService and ServiceParameters values from the AppID key */
01749     sz = sizeof buf;
01750     r = RegQueryValueExW(hkey, szLocalService, NULL, &type, (LPBYTE)buf, &sz);
01751     if (r==ERROR_SUCCESS && type==REG_SZ)
01752     {
01753         DWORD num_args = 0;
01754         LPWSTR args[1] = { NULL };
01755 
01756         /*
01757          * FIXME: I'm not really sure how to deal with the service parameters.
01758          *        I suspect that the string returned from RegQueryValueExW
01759          *        should be split into a number of arguments by spaces.
01760          *        It would make more sense if ServiceParams contained a
01761          *        REG_MULTI_SZ here, but it's a REG_SZ for the services
01762          *        that I'm interested in for the moment.
01763          */
01764         r = RegQueryValueExW(hkey, szServiceParams, NULL, &type, NULL, &sz);
01765         if (r == ERROR_SUCCESS && type == REG_SZ && sz)
01766         {
01767             args[0] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sz);
01768             num_args++;
01769             RegQueryValueExW(hkey, szServiceParams, NULL, &type, (LPBYTE)args[0], &sz);
01770         }
01771         r = start_local_service(buf, num_args, (LPCWSTR *)args);
01772         if (r != ERROR_SUCCESS)
01773             hres = REGDB_E_CLASSNOTREG; /* FIXME: check retval */
01774         HeapFree(GetProcessHeap(),0,args[0]);
01775     }
01776     else
01777     {
01778         WARN("No LocalService value\n");
01779         hres = REGDB_E_CLASSNOTREG; /* FIXME: check retval */
01780     }
01781     RegCloseKey(hkey);
01782 
01783     return hres;
01784 }
01785 
01786 
01787 static void get_localserver_pipe_name(WCHAR *pipefn, REFCLSID rclsid)
01788 {
01789     static const WCHAR wszPipeRef[] = {'\\','\\','.','\\','p','i','p','e','\\',0};
01790     strcpyW(pipefn, wszPipeRef);
01791     StringFromGUID2(rclsid, pipefn + sizeof(wszPipeRef)/sizeof(wszPipeRef[0]) - 1, CHARS_IN_GUID);
01792 }
01793 
01794 /* FIXME: should call to rpcss instead */
01795 HRESULT RPC_GetLocalClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv)
01796 {
01797     HRESULT        hres;
01798     HANDLE         hPipe;
01799     WCHAR          pipefn[100];
01800     DWORD          res, bufferlen;
01801     char           marshalbuffer[200];
01802     IStream       *pStm;
01803     LARGE_INTEGER  seekto;
01804     ULARGE_INTEGER newpos;
01805     int            tries = 0;
01806 
01807     static const int MAXTRIES = 30; /* 30 seconds */
01808 
01809     TRACE("rclsid=%s, iid=%s\n", debugstr_guid(rclsid), debugstr_guid(iid));
01810 
01811     get_localserver_pipe_name(pipefn, rclsid);
01812 
01813     while (tries++ < MAXTRIES) {
01814         TRACE("waiting for %s\n", debugstr_w(pipefn));
01815 
01816         WaitNamedPipeW( pipefn, NMPWAIT_WAIT_FOREVER );
01817         hPipe = CreateFileW(pipefn, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
01818         if (hPipe == INVALID_HANDLE_VALUE) {
01819             DWORD index;
01820             DWORD start_ticks;
01821             HANDLE process = 0;
01822             if (tries == 1) {
01823                 if ( (hres = create_local_service(rclsid)) &&
01824                      (hres = create_server(rclsid, &process)) )
01825                     return hres;
01826             } else {
01827                 WARN("Connecting to %s, no response yet, retrying: le is %u\n", debugstr_w(pipefn), GetLastError());
01828             }
01829             /* wait for one second, even if messages arrive */
01830             start_ticks = GetTickCount();
01831             do {
01832                 if (SUCCEEDED(CoWaitForMultipleHandles(0, 1000, (process != 0),
01833                                                        &process, &index)) && process && !index)
01834                 {
01835                     WARN( "server for %s failed to start\n", debugstr_guid(rclsid) );
01836                     CloseHandle( hPipe );
01837                     CloseHandle( process );
01838                     return E_NOINTERFACE;
01839                 }
01840             } while (GetTickCount() - start_ticks < 1000);
01841             if (process) CloseHandle( process );
01842             continue;
01843         }
01844         bufferlen = 0;
01845         if (!ReadFile(hPipe,marshalbuffer,sizeof(marshalbuffer),&bufferlen,NULL)) {
01846             FIXME("Failed to read marshal id from classfactory of %s.\n",debugstr_guid(rclsid));
01847             Sleep(1000);
01848             continue;
01849         }
01850         TRACE("read marshal id from pipe\n");
01851         CloseHandle(hPipe);
01852         break;
01853     }
01854     
01855     if (tries >= MAXTRIES)
01856         return E_NOINTERFACE;
01857     
01858     hres = CreateStreamOnHGlobal(0,TRUE,&pStm);
01859     if (hres) return hres;
01860     hres = IStream_Write(pStm,marshalbuffer,bufferlen,&res);
01861     if (hres) goto out;
01862     seekto.u.LowPart = 0;seekto.u.HighPart = 0;
01863     hres = IStream_Seek(pStm,seekto,STREAM_SEEK_SET,&newpos);
01864     
01865     TRACE("unmarshalling classfactory\n");
01866     hres = CoUnmarshalInterface(pStm,&IID_IClassFactory,ppv);
01867 out:
01868     IStream_Release(pStm);
01869     return hres;
01870 }
01871 
01872 
01873 struct local_server_params
01874 {
01875     CLSID clsid;
01876     IStream *stream;
01877     HANDLE ready_event;
01878     HANDLE stop_event;
01879     HANDLE thread;
01880     BOOL multi_use;
01881 };
01882 
01883 /* FIXME: should call to rpcss instead */
01884 static DWORD WINAPI local_server_thread(LPVOID param)
01885 {
01886     struct local_server_params * lsp = param;
01887     WCHAR       pipefn[100];
01888     HRESULT     hres;
01889     IStream     *pStm = lsp->stream;
01890     STATSTG     ststg;
01891     unsigned char   *buffer;
01892     int         buflen;
01893     LARGE_INTEGER   seekto;
01894     ULARGE_INTEGER  newpos;
01895     ULONG       res;
01896     BOOL multi_use = lsp->multi_use;
01897     OVERLAPPED ovl;
01898     HANDLE pipe_event, hPipe, new_pipe;
01899     DWORD  bytes;
01900 
01901     TRACE("Starting threader for %s.\n",debugstr_guid(&lsp->clsid));
01902 
01903     memset(&ovl, 0, sizeof(ovl));
01904     get_localserver_pipe_name(pipefn, &lsp->clsid);
01905     ovl.hEvent = pipe_event = CreateEventW(NULL, FALSE, FALSE, NULL);
01906 
01907     hPipe = CreateNamedPipeW( pipefn, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
01908                               PIPE_TYPE_BYTE|PIPE_WAIT, PIPE_UNLIMITED_INSTANCES,
01909                               4096, 4096, 500 /* 0.5 second timeout */, NULL );
01910     if (hPipe == INVALID_HANDLE_VALUE)
01911     {
01912         FIXME("pipe creation failed for %s, le is %u\n", debugstr_w(pipefn), GetLastError());
01913         CloseHandle(pipe_event);
01914         return 1;
01915     }
01916 
01917     SetEvent(lsp->ready_event);
01918 
01919     while (1) {
01920         if (!ConnectNamedPipe(hPipe, &ovl))
01921         {
01922             DWORD error = GetLastError();
01923             if (error == ERROR_IO_PENDING)
01924             {
01925                 HANDLE handles[2] = { pipe_event, lsp->stop_event };
01926                 DWORD ret;
01927                 ret = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
01928                 if (ret != WAIT_OBJECT_0)
01929                 {
01930                     CloseHandle(hPipe);
01931                     break;
01932                 }
01933             }
01934             /* client already connected isn't an error */
01935             else if (error != ERROR_PIPE_CONNECTED)
01936             {
01937                 ERR("ConnectNamedPipe failed with error %d\n", GetLastError());
01938                 CloseHandle(hPipe);
01939                 break;
01940             }
01941         }
01942 
01943         TRACE("marshalling IClassFactory to client\n");
01944         
01945         hres = IStream_Stat(pStm,&ststg,STATFLAG_NONAME);
01946         if (hres)
01947         {
01948             CloseHandle(hPipe);
01949             CloseHandle(pipe_event);
01950             return hres;
01951         }
01952 
01953         seekto.u.LowPart = 0;
01954         seekto.u.HighPart = 0;
01955         hres = IStream_Seek(pStm,seekto,STREAM_SEEK_SET,&newpos);
01956         if (hres) {
01957             FIXME("IStream_Seek failed, %x\n",hres);
01958             CloseHandle(hPipe);
01959             CloseHandle(pipe_event);
01960             return hres;
01961         }
01962 
01963         buflen = ststg.cbSize.u.LowPart;
01964         buffer = HeapAlloc(GetProcessHeap(),0,buflen);
01965         
01966         hres = IStream_Read(pStm,buffer,buflen,&res);
01967         if (hres) {
01968             FIXME("Stream Read failed, %x\n",hres);
01969             CloseHandle(hPipe);
01970             CloseHandle(pipe_event);
01971             HeapFree(GetProcessHeap(),0,buffer);
01972             return hres;
01973         }
01974         
01975         WriteFile(hPipe,buffer,buflen,&res,&ovl);
01976         GetOverlappedResult(hPipe, &ovl, &bytes, TRUE);
01977         HeapFree(GetProcessHeap(),0,buffer);
01978 
01979         FlushFileBuffers(hPipe);
01980         DisconnectNamedPipe(hPipe);
01981         TRACE("done marshalling IClassFactory\n");
01982 
01983         if (!multi_use)
01984         {
01985             TRACE("single use object, shutting down pipe %s\n", debugstr_w(pipefn));
01986             CloseHandle(hPipe);
01987             break;
01988         }
01989         new_pipe = CreateNamedPipeW( pipefn, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
01990                                      PIPE_TYPE_BYTE|PIPE_WAIT, PIPE_UNLIMITED_INSTANCES,
01991                                      4096, 4096, 500 /* 0.5 second timeout */, NULL );
01992         CloseHandle(hPipe);
01993         if (new_pipe == INVALID_HANDLE_VALUE)
01994         {
01995             FIXME("pipe creation failed for %s, le is %u\n", debugstr_w(pipefn), GetLastError());
01996             CloseHandle(pipe_event);
01997             return 1;
01998         }
01999         hPipe = new_pipe;
02000     }
02001     CloseHandle(pipe_event);
02002     return 0;
02003 }
02004 
02005 /* starts listening for a local server */
02006 HRESULT RPC_StartLocalServer(REFCLSID clsid, IStream *stream, BOOL multi_use, void **registration)
02007 {
02008     DWORD tid;
02009     struct local_server_params *lsp;
02010 
02011     lsp = HeapAlloc(GetProcessHeap(), 0, sizeof(*lsp));
02012     if (!lsp)
02013         return E_OUTOFMEMORY;
02014 
02015     lsp->clsid = *clsid;
02016     lsp->stream = stream;
02017     IStream_AddRef(stream);
02018     lsp->ready_event = CreateEventW(NULL, FALSE, FALSE, NULL);
02019     if (!lsp->ready_event)
02020     {
02021         HeapFree(GetProcessHeap(), 0, lsp);
02022         return HRESULT_FROM_WIN32(GetLastError());
02023     }
02024     lsp->stop_event = CreateEventW(NULL, FALSE, FALSE, NULL);
02025     if (!lsp->stop_event)
02026     {
02027         CloseHandle(lsp->ready_event);
02028         HeapFree(GetProcessHeap(), 0, lsp);
02029         return HRESULT_FROM_WIN32(GetLastError());
02030     }
02031     lsp->multi_use = multi_use;
02032 
02033     lsp->thread = CreateThread(NULL, 0, local_server_thread, lsp, 0, &tid);
02034     if (!lsp->thread)
02035     {
02036         CloseHandle(lsp->ready_event);
02037         CloseHandle(lsp->stop_event);
02038         HeapFree(GetProcessHeap(), 0, lsp);
02039         return HRESULT_FROM_WIN32(GetLastError());
02040     }
02041 
02042     WaitForSingleObject(lsp->ready_event, INFINITE);
02043     CloseHandle(lsp->ready_event);
02044     lsp->ready_event = NULL;
02045 
02046     *registration = lsp;
02047     return S_OK;
02048 }
02049 
02050 /* stops listening for a local server */
02051 void RPC_StopLocalServer(void *registration)
02052 {
02053     struct local_server_params *lsp = registration;
02054 
02055     /* signal local_server_thread to stop */
02056     SetEvent(lsp->stop_event);
02057     /* wait for it to exit */
02058     WaitForSingleObject(lsp->thread, INFINITE);
02059 
02060     IStream_Release(lsp->stream);
02061     CloseHandle(lsp->stop_event);
02062     CloseHandle(lsp->thread);
02063     HeapFree(GetProcessHeap(), 0, lsp);
02064 }

Generated on Sat May 26 2012 04:16:37 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.