I've encountered an installer that needed this... This is the last rpcrt4 update for now, I guess it's finally time to start looking at chopping up my ole32 work for submission. Log: Ove Kaaven <ovek@transgaming.com> Initial support for RPC call failures, by catching RPC server exceptions and returning simple failure packets, and throwing exceptions on the client side when unmarshalling the failure packet. ? dlls/rpcrt4/rpc_misc.h Index: dlls/rpcrt4/ndr_midl.c =================================================================== RCS file: /home/wine/wine/dlls/rpcrt4/ndr_midl.c,v retrieving revision 1.13 diff -u -r1.13 ndr_midl.c --- dlls/rpcrt4/ndr_midl.c 21 May 2003 18:22:49 -0000 1.13 +++ dlls/rpcrt4/ndr_midl.c 21 May 2003 19:56:57 -0000 @@ -106,6 +106,10 @@ pStubMsg->BufferStart = pStubMsg->RpcMsg->Buffer; pStubMsg->BufferEnd = pStubMsg->BufferStart + pStubMsg->BufferLength; pStubMsg->Buffer = pStubMsg->BufferStart; + + /* raise exception if call failed */ + if (hr == RPC_S_CALL_FAILED) RpcRaiseException(*(DWORD*)pStubMsg->Buffer); + else if (FAILED(hr)) RpcRaiseException(hr); } /*********************************************************************** Index: dlls/rpcrt4/rpc_message.c =================================================================== RCS file: /home/wine/wine/dlls/rpcrt4/rpc_message.c,v retrieving revision 1.6 diff -u -r1.6 rpc_message.c --- dlls/rpcrt4/rpc_message.c 21 May 2003 18:23:06 -0000 1.6 +++ dlls/rpcrt4/rpc_message.c 21 May 2003 19:56:57 -0000 @@ -37,6 +37,7 @@ #include "wine/debug.h" #include "rpc_binding.h" +#include "rpc_misc.h" #include "rpc_defs.h" WINE_DEFAULT_DEBUG_CHANNEL(ole); @@ -111,7 +112,9 @@ /* initialize packet header */ memset(&hdr, 0, sizeof(hdr)); hdr.rpc_ver = 4; - hdr.ptype = bind->server ? PKT_RESPONSE : PKT_REQUEST; + hdr.ptype = bind->server + ? ((pMsg->RpcFlags & WINE_RPCFLAG_EXCEPTION) ? PKT_FAULT : PKT_RESPONSE) + : PKT_REQUEST; hdr.object = *obj; /* FIXME: IIRC iff no object, the header structure excludes this elt */ hdr.if_id = (bind->server) ? sif->InterfaceId.SyntaxGUID : cif->InterfaceId.SyntaxGUID; hdr.if_vers = @@ -227,10 +230,27 @@ goto fail; } + status = RPC_S_PROTOCOL_ERROR; + + switch (hdr.ptype) { + case PKT_RESPONSE: + if (bind->server) goto fail; + break; + case PKT_REQUEST: + if (!bind->server) goto fail; + break; + case PKT_FAULT: + pMsg->RpcFlags |= WINE_RPCFLAG_EXCEPTION; + status = RPC_S_CALL_FAILED; /* ? */ + goto fail; + default: + goto fail; + } + /* success */ status = RPC_S_OK; - /* FIXME: check packet type, destination, etc? */ + /* FIXME: check destination, etc? */ break; } fail: Index: dlls/rpcrt4/rpc_server.c =================================================================== RCS file: /home/wine/wine/dlls/rpcrt4/rpc_server.c,v retrieving revision 1.16 diff -u -r1.16 rpc_server.c --- dlls/rpcrt4/rpc_server.c 21 May 2003 18:23:06 -0000 1.16 +++ dlls/rpcrt4/rpc_server.c 21 May 2003 19:56:58 -0000 @@ -33,8 +33,11 @@ #include "rpc.h" #include "wine/debug.h" +#include "wine/exception.h" +#include "msvcrt/excpt.h" #include "rpc_server.h" +#include "rpc_misc.h" #include "rpc_defs.h" #define MAX_THREADS 128 @@ -63,7 +66,7 @@ static RpcPacket* spacket_tail; static HANDLE server_sem; -static DWORD worker_count, worker_free; +static DWORD worker_count, worker_free, worker_tls; static RpcServerInterface* RPCRT4_find_interface(UUID* object, UUID* if_id) { @@ -110,6 +113,18 @@ return packet; } +static WINE_EXCEPTION_FILTER(rpc_filter) +{ + PRPC_MESSAGE msg; + msg = TlsGetValue(worker_tls); + I_RpcFreeBuffer(msg); + msg->RpcFlags |= WINE_RPCFLAG_EXCEPTION; + msg->BufferLength = sizeof(DWORD); + I_RpcGetBuffer(msg); + *(DWORD*)msg->Buffer = GetExceptionCode(); + return EXCEPTION_EXECUTE_HANDLER; +} + static void RPCRT4_process_packet(RpcConnection* conn, RpcPktHdr* hdr, void* buf) { RpcBinding* pbind; @@ -117,6 +132,7 @@ RpcServerInterface* sif; RPC_DISPATCH_FUNCTION func; + TlsSetValue(worker_tls, &msg); memset(&msg, 0, sizeof(msg)); msg.BufferLength = hdr->len; msg.Buffer = buf; @@ -152,7 +168,12 @@ MAKEWORD(hdr->drep[2], 0)); /* dispatch */ - if (func) func(&msg); + __TRY { + if (func) func(&msg); + } __EXCEPT(rpc_filter) { + /* failure packet was created in rpc_filter */ + TRACE("exception caught, returning failure packet\n"); + } __ENDTRY /* send response packet */ I_RpcSend(&msg); @@ -176,6 +197,7 @@ HeapFree(GetProcessHeap(), 0, buf); I_RpcFreeBuffer(&msg); msg.Buffer = NULL; + TlsSetValue(worker_tls, NULL); } static DWORD CALLBACK RPCRT4_worker_thread(LPVOID the_arg) @@ -411,6 +433,7 @@ if (! ++listen_count) { if (!mgr_event) mgr_event = CreateEventA(NULL, TRUE, FALSE, NULL); if (!server_sem) server_sem = CreateSemaphoreA(NULL, 0, MAX_THREADS, NULL); + if (!worker_tls) worker_tls = TlsAlloc(); std_listen = TRUE; server_thread = CreateThread(NULL, 0, RPCRT4_server_thread, NULL, 0, NULL); LeaveCriticalSection(&listen_cs); --- /dev/null 2003-01-10 01:23:22.000000000 +0100 +++ dlls/rpcrt4/rpc_misc.h 2003-05-21 21:55:52.000000000 +0200 @@ -0,0 +1,13 @@ +/* + * RPC definitions + * + * Copyright 2003 Ove Kåven, TransGaming Technologies + */ + +#ifndef __WINE_RPC_MISC_H +#define __WINE_RPC_MISC_H + +/* flags for RPC_MESSAGE.RpcFlags */ +#define WINE_RPCFLAG_EXCEPTION 0x0001 + +#endif /* __WINE_RPC_MISC_H */