At this point, things should start getting a lot more interesting. Aside from the missing un-marshall method for conformant strings, (which I'll have to get to soon) I supposedly have all the infrastructure in place to execute the "DCE Interop" RPC sample from MSDN. Of course, there may be stuff I'm forgetting to do; these things ought to make themselves evident soon. So far, no dice, it fails to open the named pipe (using ncacn_np). Haven't done much investigation into this yet, it's probably something stupid and/or trivial. There is still a LOT of work to do... this is just the tip of the iceberg, but I will nevertheless have to post a w00t or two once I get a successful RPC to occur! LICENSE: X11 CHANGELOG: * dlls/rpcrt4: ndr_marshall.c, ndr_midl.c, rpc_message.c: Greg Turner <gmturner007@ameritech.net> - use memset instead of ZeroMemory, just to be consistent with Ove's code. - add some assertions where assumptions are made (need way more) - plug the binding handle into the RPC_MESSAGE during NdrGetBuffer - Implement NdrSendReceive - attempt to support client and server bindings in I_RpcSend[Receive] -- gmt "Oh, and of course, the fastest way to dig a tunnel is to dig at both sides." -- The Linux Advanced Routing HOWTO
diff -ur -x CVS -x 'bigdif*' ../wine.test/dlls/rpcrt4/ndr_marshall.c ./dlls/rpcrt4/ndr_marshall.c --- ../wine.test/dlls/rpcrt4/ndr_marshall.c 2002-10-24 00:46:58.000000000 -0500 +++ ./dlls/rpcrt4/ndr_marshall.c 2002-10-25 00:04:08.000000000 -0500 @@ -58,7 +58,7 @@ assert( (pStubMsg->BufferLength > (len + 13)) && (pStubMsg->Buffer != NULL) ); /* in DCE terminology this is a Conformant Varying String */ c = pStubMsg->Buffer; - ZeroMemory(c, 12); + memset(c, 0, 12); *((UINT32 *)c) = len + 1; /* max length: strlen + 1 (for '\0') */ c += 8; /* offset: 0 */ *((UINT32 *)c) = len + 1; /* actual length: (same) */ diff -ur -x CVS -x 'bigdif*' ../wine.test/dlls/rpcrt4/ndr_midl.c ./dlls/rpcrt4/ndr_midl.c --- ../wine.test/dlls/rpcrt4/ndr_midl.c 2002-10-24 00:46:58.000000000 -0500 +++ ./dlls/rpcrt4/ndr_midl.c 2002-10-25 02:48:38.000000000 -0500 @@ -24,6 +24,7 @@ #include <stdio.h> #include <string.h> +#include <assert.h> #include "windef.h" #include "winbase.h" @@ -198,7 +199,10 @@ { TRACE("(stubmsg == ^%p, buflen == %lu, handle == %p): wild guess.\n", stubmsg, buflen, handle); - /* FIXME: What are we supposed to do with the handle? */ + assert( stubmsg && stubmsg->RpcMsg ); + + /* I guess this is our chance to put the binding handle into the RPC_MESSAGE */ + stubmsg->RpcMsg->Handle = handle; stubmsg->RpcMsg->BufferLength = buflen; if (I_RpcGetBuffer(stubmsg->RpcMsg) != S_OK) @@ -224,6 +228,26 @@ */ unsigned char *WINAPI NdrSendReceive( MIDL_STUB_MESSAGE *stubmsg, unsigned char *buffer ) { - FIXME("stub\n"); + TRACE("(stubmsg == ^%p, buffer == ^%p)\n", stubmsg, buffer); + + /* FIXME: how to handle errors? (raise exception?) */ + if (!stubmsg) { + ERR("NULL stub message. No action taken.\n"); + return NULL; + } + if (!stubmsg->RpcMsg) { + ERR("RPC Message not present in stub message. No action taken.\n"); + return NULL; + } + if (stubmsg->RpcMsg->Buffer != buffer) { + ERR("Ambiguous buffer doesn't match rpc message buffer. No action taken.\n"); + return NULL; + } + + if (I_RpcSendReceive(stubmsg->RpcMsg) != RPC_S_OK) { + WARN("I_RpcSendReceive did not return success.\n"); + } + + /* FIXME: is this the right return value? */ return NULL; } diff -ur -x CVS -x 'bigdif*' ../wine.test/dlls/rpcrt4/rpc_message.c ./dlls/rpcrt4/rpc_message.c --- ../wine.test/dlls/rpcrt4/rpc_message.c 2002-10-10 13:55:24.000000000 -0500 +++ ./dlls/rpcrt4/rpc_message.c 2002-10-25 02:48:23.000000000 -0500 @@ -72,18 +72,21 @@ RPC_STATUS WINAPI I_RpcSend(PRPC_MESSAGE pMsg) { RpcBinding* bind = (RpcBinding*)pMsg->Handle; - RPC_CLIENT_INTERFACE* cif; + RPC_CLIENT_INTERFACE* cif = NULL; + RPC_SERVER_INTERFACE* sif = NULL; RPC_STATUS status; RpcPktHdr hdr; TRACE("(%p)\n", pMsg); if (!bind) return RPC_S_INVALID_BINDING; - /* I'll only implement this for client handles for now */ - if (bind->server) return RPC_S_WRONG_KIND_OF_BINDING; - - cif = pMsg->RpcInterfaceInformation; - if (!cif) return RPC_S_INTERFACE_NOT_FOUND; /* ? */ + if (bind->server) { + sif = pMsg->RpcInterfaceInformation; + if (!sif) return RPC_S_INTERFACE_NOT_FOUND; /* ? */ + } else { + cif = pMsg->RpcInterfaceInformation; + if (!cif) return RPC_S_INTERFACE_NOT_FOUND; /* ? */ + } status = RPCRT4_OpenBinding(bind); if (status != RPC_S_OK) return status; @@ -92,10 +95,12 @@ memset(&hdr, 0, sizeof(hdr)); hdr.rpc_ver = 4; hdr.ptype = PKT_REQUEST; - hdr.object = bind->ObjectUuid; - hdr.if_id = cif->InterfaceId.SyntaxGUID; - hdr.if_vers = MAKELONG(cif->InterfaceId.SyntaxVersion.MinorVersion, - cif->InterfaceId.SyntaxVersion.MajorVersion); + hdr.object = bind->ObjectUuid; /* 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 = + (bind->server) ? + MAKELONG(sif->InterfaceId.SyntaxVersion.MinorVersion, sif->InterfaceId.SyntaxVersion.MajorVersion) : + MAKELONG(cif->InterfaceId.SyntaxVersion.MinorVersion, cif->InterfaceId.SyntaxVersion.MajorVersion); hdr.opnum = pMsg->ProcNum; hdr.len = pMsg->BufferLength; @@ -122,9 +127,6 @@ TRACE("(%p)\n", pMsg); if (!bind) return RPC_S_INVALID_BINDING; - /* I'll only implement this for client handles for now */ - if (bind->server) return RPC_S_WRONG_KIND_OF_BINDING; - status = RPCRT4_OpenBinding(bind); if (status != RPC_S_OK) return status;