2 * COM proxy implementation
4 * Copyright 2001 Ove Kåven, TransGaming Technologies
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 * TODO: Handle non-i386 architectures
36 #include "wine/debug.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(ole);
42 /* I don't know what MS's std proxy structure looks like,
43 so this probably doesn't match, but that shouldn't matter */
45 const IRpcProxyBufferVtbl *lpVtbl;
48 const MIDL_STUBLESS_PROXY_INFO *stubless;
52 LPPSFACTORYBUFFER pPSFactory;
53 LPRPCCHANNELBUFFER pChannel;
54 struct StublessThunk *thunks;
57 static const IRpcProxyBufferVtbl StdProxy_Vtbl;
59 #define ICOM_THIS_MULTI(impl,field,iface) impl* const This=(impl*)((char*)(iface) - offsetof(impl,field))
65 struct StublessThunk {
77 /* adjust the stack size since we don't use Windows's method */
78 #define STACK_ADJUST sizeof(DWORD)
80 #define FILL_STUBLESS(x,idx,stk) \
81 x->push = 0x68; /* pushl [immediate] */ \
83 x->call = 0xe8; /* call [near] */ \
84 x->handler = (char*)ObjectStubless - (char*)&x->ret; \
85 x->ret = 0xc2; /* ret [immediate] */ \
87 x->pad[0] = 0x8d; /* leal (%esi),%esi */ \
91 static HRESULT WINAPI ObjectStubless(DWORD index)
93 char *args = (char*)(&index + 2);
94 LPVOID iface = *(LPVOID*)args;
96 ICOM_THIS_MULTI(StdProxyImpl,PVtbl,iface);
98 PFORMAT_STRING fs = This->stubless->ProcFormatString + This->stubless->FormatStringOffset[index];
99 unsigned bytes = *(const WORD*)(fs+8) - STACK_ADJUST;
100 TRACE("(%p)->(%d)([%d bytes]) ret=%08x\n", iface, index, bytes, *(DWORD*)(args+bytes));
102 return NdrClientCall2(This->stubless->pStubDesc, fs, args);
107 /* can't do that on this arch */
108 struct StublessThunk { int dummy; };
109 #define FILL_STUBLESS(x,idx,stk) \
110 ERR("stubless proxies are not supported on this architecture\n");
111 #define STACK_ADJUST 0
113 #endif /* __i386__ */
115 HRESULT StdProxy_Construct(REFIID riid,
117 const ProxyFileInfo *ProxyInfo,
119 LPPSFACTORYBUFFER pPSFactory,
120 LPRPCPROXYBUFFER *ppProxy,
124 const MIDL_STUBLESS_PROXY_INFO *stubless = NULL;
125 PCInterfaceName name = ProxyInfo->pNamesArray[Index];
126 CInterfaceProxyVtbl *vtbl = ProxyInfo->pProxyVtblList[Index];
128 TRACE("(%p,%p,%p,%p,%p) %s\n", pUnkOuter, vtbl, pPSFactory, ppProxy, ppvObj, name);
130 /* TableVersion = 2 means it is the stubless version of CInterfaceProxyVtbl */
131 if (ProxyInfo->TableVersion > 1) {
132 stubless = *(const void **)vtbl;
133 vtbl = (CInterfaceProxyVtbl *)((const void **)vtbl + 1);
134 TRACE("stubless=%p\n", stubless);
137 TRACE("iid=%s\n", debugstr_guid(vtbl->header.piid));
138 TRACE("vtbl=%p\n", vtbl->Vtbl);
140 if (!IsEqualGUID(vtbl->header.piid, riid)) {
141 ERR("IID mismatch during proxy creation\n");
142 return RPC_E_UNEXPECTED;
145 This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(StdProxyImpl));
146 if (!This) return E_OUTOFMEMORY;
149 CInterfaceStubVtbl *svtbl = ProxyInfo->pStubVtblList[Index];
150 ULONG i, count = svtbl->header.DispatchTableCount;
151 /* Maybe the original vtbl is just modified directly to point at
152 * ObjectStublessClientXXX thunks in real Windows, but I don't like it
154 TRACE("stubless thunks: count=%d\n", count);
155 This->thunks = HeapAlloc(GetProcessHeap(),0,sizeof(struct StublessThunk)*count);
156 This->PVtbl = HeapAlloc(GetProcessHeap(),0,sizeof(LPVOID)*count);
157 for (i=0; i<count; i++) {
158 struct StublessThunk *thunk = &This->thunks[i];
159 if (vtbl->Vtbl[i] == (LPVOID)-1) {
160 PFORMAT_STRING fs = stubless->ProcFormatString + stubless->FormatStringOffset[i];
161 unsigned bytes = *(const WORD*)(fs+8) - STACK_ADJUST;
162 TRACE("method %d: stacksize=%d\n", i, bytes);
163 FILL_STUBLESS(thunk, i, bytes)
164 This->PVtbl[i] = thunk;
167 memset(thunk, 0, sizeof(struct StublessThunk));
168 This->PVtbl[i] = vtbl->Vtbl[i];
173 This->PVtbl = vtbl->Vtbl;
175 if (!pUnkOuter) pUnkOuter = (IUnknown *)This;
176 This->lpVtbl = &StdProxy_Vtbl;
177 /* one reference for the proxy */
179 This->stubless = stubless;
180 This->piid = vtbl->header.piid;
181 This->pUnkOuter = pUnkOuter;
183 This->pPSFactory = pPSFactory;
184 This->pChannel = NULL;
185 *ppProxy = (LPRPCPROXYBUFFER)&This->lpVtbl;
186 *ppvObj = &This->PVtbl;
187 IUnknown_AddRef((IUnknown *)*ppvObj);
188 IPSFactoryBuffer_AddRef(pPSFactory);
193 static void StdProxy_Destruct(LPRPCPROXYBUFFER iface)
195 ICOM_THIS_MULTI(StdProxyImpl,lpVtbl,iface);
198 IRpcProxyBuffer_Disconnect(iface);
200 IPSFactoryBuffer_Release(This->pPSFactory);
202 HeapFree(GetProcessHeap(),0,This->PVtbl);
203 HeapFree(GetProcessHeap(),0,This->thunks);
205 HeapFree(GetProcessHeap(),0,This);
208 static HRESULT WINAPI StdProxy_QueryInterface(LPRPCPROXYBUFFER iface,
212 ICOM_THIS_MULTI(StdProxyImpl,lpVtbl,iface);
213 TRACE("(%p)->QueryInterface(%s,%p)\n",This,debugstr_guid(riid),obj);
215 if (IsEqualGUID(&IID_IUnknown,riid) ||
216 IsEqualGUID(This->piid,riid)) {
218 InterlockedIncrement(&This->RefCount);
222 if (IsEqualGUID(&IID_IRpcProxyBuffer,riid)) {
223 *obj = &This->lpVtbl;
224 InterlockedIncrement(&This->RefCount);
228 return E_NOINTERFACE;
231 static ULONG WINAPI StdProxy_AddRef(LPRPCPROXYBUFFER iface)
233 ICOM_THIS_MULTI(StdProxyImpl,lpVtbl,iface);
234 TRACE("(%p)->AddRef()\n",This);
236 return InterlockedIncrement(&This->RefCount);
239 static ULONG WINAPI StdProxy_Release(LPRPCPROXYBUFFER iface)
242 ICOM_THIS_MULTI(StdProxyImpl,lpVtbl,iface);
243 TRACE("(%p)->Release()\n",This);
245 refs = InterlockedDecrement(&This->RefCount);
247 StdProxy_Destruct((LPRPCPROXYBUFFER)&This->lpVtbl);
251 static HRESULT WINAPI StdProxy_Connect(LPRPCPROXYBUFFER iface,
252 LPRPCCHANNELBUFFER pChannel)
254 ICOM_THIS_MULTI(StdProxyImpl,lpVtbl,iface);
255 TRACE("(%p)->Connect(%p)\n",This,pChannel);
257 This->pChannel = pChannel;
258 IRpcChannelBuffer_AddRef(pChannel);
262 static VOID WINAPI StdProxy_Disconnect(LPRPCPROXYBUFFER iface)
264 ICOM_THIS_MULTI(StdProxyImpl,lpVtbl,iface);
265 TRACE("(%p)->Disconnect()\n",This);
267 IRpcChannelBuffer_Release(This->pChannel);
268 This->pChannel = NULL;
271 static const IRpcProxyBufferVtbl StdProxy_Vtbl =
273 StdProxy_QueryInterface,
280 static void StdProxy_GetChannel(LPVOID iface,
281 LPRPCCHANNELBUFFER *ppChannel)
283 ICOM_THIS_MULTI(StdProxyImpl,PVtbl,iface);
284 TRACE("(%p)->GetChannel(%p) %s\n",This,ppChannel,This->name);
286 *ppChannel = This->pChannel;
289 static void StdProxy_GetIID(LPVOID iface,
292 ICOM_THIS_MULTI(StdProxyImpl,PVtbl,iface);
293 TRACE("(%p)->GetIID(%p) %s\n",This,ppiid,This->name);
298 HRESULT WINAPI IUnknown_QueryInterface_Proxy(LPUNKNOWN iface,
302 ICOM_THIS_MULTI(StdProxyImpl,PVtbl,iface);
303 TRACE("(%p)->QueryInterface(%s,%p) %s\n",This,debugstr_guid(riid),ppvObj,This->name);
304 return IUnknown_QueryInterface(This->pUnkOuter,riid,ppvObj);
307 ULONG WINAPI IUnknown_AddRef_Proxy(LPUNKNOWN iface)
309 ICOM_THIS_MULTI(StdProxyImpl,PVtbl,iface);
310 TRACE("(%p)->AddRef() %s\n",This,This->name);
311 return IUnknown_AddRef(This->pUnkOuter);
314 ULONG WINAPI IUnknown_Release_Proxy(LPUNKNOWN iface)
316 ICOM_THIS_MULTI(StdProxyImpl,PVtbl,iface);
317 TRACE("(%p)->Release() %s\n",This,This->name);
318 return IUnknown_Release(This->pUnkOuter);
321 /***********************************************************************
322 * NdrProxyInitialize [RPCRT4.@]
324 void WINAPI NdrProxyInitialize(void *This,
325 PRPC_MESSAGE pRpcMsg,
326 PMIDL_STUB_MESSAGE pStubMsg,
327 PMIDL_STUB_DESC pStubDescriptor,
328 unsigned int ProcNum)
330 TRACE("(%p,%p,%p,%p,%d)\n", This, pRpcMsg, pStubMsg, pStubDescriptor, ProcNum);
331 NdrClientInitializeNew(pRpcMsg, pStubMsg, pStubDescriptor, ProcNum);
332 StdProxy_GetChannel(This, &pStubMsg->pRpcChannelBuffer);
333 IRpcChannelBuffer_GetDestCtx(pStubMsg->pRpcChannelBuffer,
334 &pStubMsg->dwDestContext,
335 &pStubMsg->pvDestContext);
336 TRACE("channel=%p\n", pStubMsg->pRpcChannelBuffer);
339 /***********************************************************************
340 * NdrProxyGetBuffer [RPCRT4.@]
342 void WINAPI NdrProxyGetBuffer(void *This,
343 PMIDL_STUB_MESSAGE pStubMsg)
346 const IID *riid = NULL;
348 TRACE("(%p,%p)\n", This, pStubMsg);
349 pStubMsg->RpcMsg->BufferLength = pStubMsg->BufferLength;
350 pStubMsg->dwStubPhase = PROXY_GETBUFFER;
351 StdProxy_GetIID(This, &riid);
352 hr = IRpcChannelBuffer_GetBuffer(pStubMsg->pRpcChannelBuffer,
353 (RPCOLEMESSAGE*)pStubMsg->RpcMsg,
357 RpcRaiseException(hr);
360 pStubMsg->fBufferValid = TRUE;
361 pStubMsg->BufferStart = pStubMsg->RpcMsg->Buffer;
362 pStubMsg->BufferEnd = pStubMsg->BufferStart + pStubMsg->BufferLength;
363 pStubMsg->Buffer = pStubMsg->BufferStart;
364 pStubMsg->dwStubPhase = PROXY_MARSHAL;
367 /***********************************************************************
368 * NdrProxySendReceive [RPCRT4.@]
370 void WINAPI NdrProxySendReceive(void *This,
371 PMIDL_STUB_MESSAGE pStubMsg)
376 TRACE("(%p,%p)\n", This, pStubMsg);
378 if (!pStubMsg->pRpcChannelBuffer)
380 WARN("Trying to use disconnected proxy %p\n", This);
381 RpcRaiseException(RPC_E_DISCONNECTED);
384 pStubMsg->dwStubPhase = PROXY_SENDRECEIVE;
385 /* avoid sending uninitialised parts of the buffer on the wire */
386 pStubMsg->RpcMsg->BufferLength = pStubMsg->Buffer - (unsigned char *)pStubMsg->RpcMsg->Buffer;
387 hr = IRpcChannelBuffer_SendReceive(pStubMsg->pRpcChannelBuffer,
388 (RPCOLEMESSAGE*)pStubMsg->RpcMsg,
390 pStubMsg->dwStubPhase = PROXY_UNMARSHAL;
391 pStubMsg->BufferLength = pStubMsg->RpcMsg->BufferLength;
392 pStubMsg->BufferStart = pStubMsg->RpcMsg->Buffer;
393 pStubMsg->BufferEnd = pStubMsg->BufferStart + pStubMsg->BufferLength;
394 pStubMsg->Buffer = pStubMsg->BufferStart;
396 /* raise exception if call failed */
397 if (hr == RPC_S_CALL_FAILED) RpcRaiseException(*(DWORD*)pStubMsg->Buffer);
398 else if (FAILED(hr)) RpcRaiseException(hr);
401 /***********************************************************************
402 * NdrProxyFreeBuffer [RPCRT4.@]
404 void WINAPI NdrProxyFreeBuffer(void *This,
405 PMIDL_STUB_MESSAGE pStubMsg)
407 TRACE("(%p,%p)\n", This, pStubMsg);
409 if (pStubMsg->fBufferValid)
411 IRpcChannelBuffer_FreeBuffer(pStubMsg->pRpcChannelBuffer,
412 (RPCOLEMESSAGE*)pStubMsg->RpcMsg);
413 pStubMsg->fBufferValid = TRUE;
417 /***********************************************************************
418 * NdrProxyErrorHandler [RPCRT4.@]
420 HRESULT WINAPI NdrProxyErrorHandler(DWORD dwExceptionCode)
422 WARN("(0x%08x): a proxy call failed\n", dwExceptionCode);
424 if (FAILED(dwExceptionCode))
425 return dwExceptionCode;
427 return HRESULT_FROM_WIN32(dwExceptionCode);
431 CreateProxyFromTypeInfo( LPTYPEINFO pTypeInfo, LPUNKNOWN pUnkOuter, REFIID riid,
432 LPRPCPROXYBUFFER *ppProxy, LPVOID *ppv )
434 typedef INT (WINAPI *MessageBoxA)(HWND,LPCSTR,LPCSTR,UINT);
435 HMODULE hUser32 = LoadLibraryA("user32");
436 MessageBoxA pMessageBoxA = (void *)GetProcAddress(hUser32, "MessageBoxA");
438 FIXME("%p %p %s %p %p\n", pTypeInfo, pUnkOuter, debugstr_guid(riid), ppProxy, ppv);
442 "The native implementation of OLEAUT32.DLL cannot be used "
443 "with Wine's RPCRT4.DLL. Remove OLEAUT32.DLL and try again.\n",
444 "Wine: Unimplemented CreateProxyFromTypeInfo",