Stubs for RpcServerUseProtseqA, RpcServerUseProtseqW.
[wine] / dlls / rpcrt4 / rpc_server.c
1 /*
2  * RPC server API
3  *
4  * Copyright 2001 Ove Kåven, TransGaming Technologies
5  *
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.
10  *
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.
15  *
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  * TODO:
21  *  - a whole lot
22  */
23
24 #include <stdio.h>
25 #include <string.h>
26
27 #include "windef.h"
28 #include "winbase.h"
29 #include "winerror.h"
30 #include "winreg.h"
31
32 #include "rpc.h"
33
34 #include "wine/debug.h"
35
36 #include "rpc_server.h"
37 #include "rpc_defs.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(ole);
40
41 static RpcServerProtseq* protseqs;
42 static RpcServerInterface* ifs;
43
44 static CRITICAL_SECTION server_cs = CRITICAL_SECTION_INIT("RpcServer");
45 static BOOL std_listen;
46 static LONG listen_count = -1;
47 static HANDLE mgr_event, server_thread;
48
49 static RpcServerInterface* RPCRT4_find_interface(UUID* object, UUID* if_id)
50 {
51   UUID* MgrType = NULL;
52   RpcServerInterface* cif = NULL;
53   RPC_STATUS status;
54
55   /* FIXME: object -> MgrType */
56   EnterCriticalSection(&server_cs);
57   cif = ifs;
58   while (cif) {
59     if (UuidEqual(if_id, &cif->If->InterfaceId.SyntaxGUID, &status) &&
60        UuidEqual(MgrType, &cif->MgrTypeUuid, &status) &&
61        (std_listen || (cif->Flags & RPC_IF_AUTOLISTEN))) break;
62     cif = cif->Next;
63   }
64   LeaveCriticalSection(&server_cs);
65   return cif;
66 }
67
68 static DWORD CALLBACK RPCRT4_io_thread(LPVOID the_arg)
69 {
70   RpcBinding* bind = (RpcBinding*)the_arg;
71   RpcPktHdr hdr;
72   DWORD dwRead;
73   RPC_MESSAGE msg;
74   RpcServerInterface* sif;
75   RPC_DISPATCH_FUNCTION func;
76
77   memset(&msg, 0, sizeof(msg));
78   msg.Handle = (RPC_BINDING_HANDLE)bind;
79
80   for (;;) {
81     /* read packet header */
82 #ifdef OVERLAPPED_WORKS
83     if (!ReadFile(bind->conn, &hdr, sizeof(hdr), &dwRead, &bind->ovl)) {
84       DWORD err = GetLastError();
85       if (err != ERROR_IO_PENDING) {
86         TRACE("connection lost, error=%08lx\n", err);
87         break;
88       }
89       if (!GetOverlappedResult(bind->conn, &bind->ovl, &dwRead, TRUE)) break;
90     }
91 #else
92     if (!ReadFile(bind->conn, &hdr, sizeof(hdr), &dwRead, NULL)) {
93       TRACE("connection lost, error=%08lx\n", GetLastError());
94       break;
95     }
96 #endif
97     if (dwRead != sizeof(hdr)) {
98       TRACE("protocol error\n");
99       break;
100     }
101
102     /* read packet body */
103     msg.BufferLength = hdr.len;
104     msg.Buffer = HeapAlloc(GetProcessHeap(), 0, msg.BufferLength);
105 #ifdef OVERLAPPED_WORKS
106     if (!ReadFile(bind->conn, msg.Buffer, msg.BufferLength, &dwRead, &bind->ovl)) {
107       DWORD err = GetLastError();
108       if (err != ERROR_IO_PENDING) {
109         TRACE("connection lost, error=%08lx\n", err);
110         break;
111       }
112       if (!GetOverlappedResult(bind->conn, &bind->ovl, &dwRead, TRUE)) break;
113     }
114 #else
115     if (!ReadFile(bind->conn, msg.Buffer, msg.BufferLength, &dwRead, NULL)) {
116       TRACE("connection lost, error=%08lx\n", GetLastError());
117       break;
118     }
119 #endif
120     if (dwRead != hdr.len) {
121       TRACE("protocol error\n");
122       break;
123     }
124
125     sif = RPCRT4_find_interface(&hdr.object, &hdr.if_id);
126     if (sif) {
127       msg.RpcInterfaceInformation = sif->If;
128       /* associate object with binding (this is a bit of a hack...
129        * a new binding should probably be created for each object) */
130       RPCRT4_SetBindingObject(bind, &hdr.object);
131       /* process packet*/
132       switch (hdr.ptype) {
133       case PKT_REQUEST:
134        /* find dispatch function */
135        msg.ProcNum = hdr.opnum;
136        if (sif->Flags & RPC_IF_OLE) {
137          /* native ole32 always gives us a dispatch table with a single entry
138           * (I assume that's a wrapper for IRpcStubBuffer::Invoke) */
139          func = *sif->If->DispatchTable->DispatchTable;
140        } else {
141          if (msg.ProcNum >= sif->If->DispatchTable->DispatchTableCount) {
142            ERR("invalid procnum\n");
143            func = NULL;
144          }
145          func = sif->If->DispatchTable->DispatchTable[msg.ProcNum];
146        }
147
148        /* dispatch */
149        if (func) func(&msg);
150
151        /* prepare response packet */
152        hdr.ptype = PKT_RESPONSE;
153        break;
154       default:
155        ERR("unknown packet type\n");
156        goto no_reply;
157       }
158
159       /* write reply packet */
160       hdr.len = msg.BufferLength;
161       WriteFile(bind->conn, &hdr, sizeof(hdr), NULL, NULL);
162       WriteFile(bind->conn, msg.Buffer, msg.BufferLength, NULL, NULL);
163
164     no_reply:
165       /* un-associate object */
166       RPCRT4_SetBindingObject(bind, NULL);
167       msg.RpcInterfaceInformation = NULL;
168     }
169     else {
170       ERR("got RPC packet to unregistered interface %s\n", debugstr_guid(&hdr.if_id));
171     }
172
173     /* clean up */
174     HeapFree(GetProcessHeap(), 0, msg.Buffer);
175     msg.Buffer = NULL;
176   }
177   if (msg.Buffer) HeapFree(GetProcessHeap(), 0, msg.Buffer);
178   RPCRT4_DestroyBinding(bind);
179   return 0;
180 }
181
182 static void RPCRT4_new_client(RpcBinding* bind)
183 {
184   bind->thread = CreateThread(NULL, 0, RPCRT4_io_thread, bind, 0, NULL);
185 }
186
187 static DWORD CALLBACK RPCRT4_server_thread(LPVOID the_arg)
188 {
189   HANDLE m_event = mgr_event, b_handle;
190   HANDLE *objs = NULL;
191   DWORD count, res;
192   RpcServerProtseq* cps;
193   RpcBinding* bind;
194   RpcBinding* cbind;
195
196   for (;;) {
197     EnterCriticalSection(&server_cs);
198     /* open and count bindings */
199     count = 1;
200     cps = protseqs;
201     while (cps) {
202       bind = cps->bind;
203       while (bind) {
204        RPCRT4_OpenBinding(bind);
205         if (bind->ovl.hEvent) count++;
206         bind = bind->Next;
207       }
208       cps = cps->Next;
209     }
210     /* make array of bindings */
211     objs = HeapReAlloc(GetProcessHeap(), 0, objs, count*sizeof(HANDLE));
212     objs[0] = m_event;
213     count = 1;
214     cps = protseqs;
215     while (cps) {
216       bind = cps->bind;
217       while (bind) {
218         if (bind->ovl.hEvent) objs[count++] = bind->ovl.hEvent;
219         bind = bind->Next;
220       }
221       cps = cps->Next;
222     }
223     LeaveCriticalSection(&server_cs);
224
225     /* start waiting */
226     res = WaitForMultipleObjects(count, objs, FALSE, INFINITE);
227     if (res == WAIT_OBJECT_0) {
228       if (listen_count == -1) break;
229     }
230     else if (res == WAIT_FAILED) {
231       ERR("wait failed\n");
232     }
233     else {
234       b_handle = objs[res - WAIT_OBJECT_0];
235       /* find which binding got a RPC */
236       EnterCriticalSection(&server_cs);
237       bind = NULL;
238       cps = protseqs;
239       while (cps) {
240         bind = cps->bind;
241         while (bind) {
242           if (bind->ovl.hEvent == b_handle) break;
243           bind = bind->Next;
244         }
245         if (bind) break;
246         cps = cps->Next;
247       }
248       cbind = NULL;
249       if (bind) RPCRT4_SpawnBinding(&cbind, bind);
250       LeaveCriticalSection(&server_cs);
251       if (!bind) {
252         ERR("failed to locate binding for handle %p\n", b_handle);
253       }
254       if (cbind) RPCRT4_new_client(cbind);
255     }
256   }
257   HeapFree(GetProcessHeap(), 0, objs);
258   EnterCriticalSection(&server_cs);
259   /* close bindings */
260   cps = protseqs;
261   while (cps) {
262     bind = cps->bind;
263     while (bind) {
264       RPCRT4_CloseBinding(bind);
265       bind = bind->Next;
266     }
267     cps = cps->Next;
268   }
269   LeaveCriticalSection(&server_cs);
270   return 0;
271 }
272
273 static void RPCRT4_start_listen(void)
274 {
275   TRACE("\n");
276   if (!InterlockedIncrement(&listen_count)) {
277     mgr_event = CreateEventA(NULL, FALSE, FALSE, NULL);
278     server_thread = CreateThread(NULL, 0, RPCRT4_server_thread, NULL, 0, NULL);
279   }
280   else SetEvent(mgr_event);
281 }
282
283 /* not used (WTF?) ---------------------------
284
285 static void RPCRT4_stop_listen(void)
286 {
287   HANDLE m_event = mgr_event;
288   if (InterlockedDecrement(&listen_count) < 0)
289     SetEvent(m_event);
290 }
291
292 --------------------- */
293
294 static RPC_STATUS RPCRT4_use_protseq(RpcServerProtseq* ps)
295 {
296   RPCRT4_CreateBindingA(&ps->bind, TRUE, ps->Protseq);
297   RPCRT4_CompleteBindingA(ps->bind, NULL, ps->Endpoint, NULL);
298
299   EnterCriticalSection(&server_cs);
300   ps->Next = protseqs;
301   protseqs = ps;
302   LeaveCriticalSection(&server_cs);
303
304   if (listen_count >= 0) SetEvent(mgr_event);
305
306   return RPC_S_OK;
307 }
308
309 /***********************************************************************
310  *             RpcServerInqBindings (RPCRT4.@)
311  */
312 RPC_STATUS WINAPI RpcServerInqBindings( RPC_BINDING_VECTOR** BindingVector )
313 {
314   RPC_STATUS status;
315   DWORD count;
316   RpcServerProtseq* ps;
317   RpcBinding* bind;
318
319   if (BindingVector)
320     TRACE("(*BindingVector == ^%p)\n", *BindingVector);
321   else
322     ERR("(BindingVector == ^null!!?)\n");
323
324   EnterCriticalSection(&server_cs);
325   /* count bindings */
326   count = 0;
327   ps = protseqs;
328   while (ps) {
329     bind = ps->bind;
330     while (bind) {
331       count++;
332       bind = bind->Next;
333     }
334     ps = ps->Next;
335   }
336   if (count) {
337     /* export bindings */
338     *BindingVector = HeapAlloc(GetProcessHeap(), 0,
339                               sizeof(RPC_BINDING_VECTOR) +
340                               sizeof(RPC_BINDING_HANDLE)*(count-1));
341     (*BindingVector)->Count = count;
342     count = 0;
343     ps = protseqs;
344     while (ps) {
345       bind = ps->bind;
346       while (bind) {
347        RPCRT4_ExportBinding((RpcBinding**)&(*BindingVector)->BindingH[count],
348                             bind);
349        count++;
350        bind = bind->Next;
351       }
352       ps = ps->Next;
353     }
354     status = RPC_S_OK;
355   } else {
356     *BindingVector = NULL;
357     status = RPC_S_NO_BINDINGS;
358   }
359   LeaveCriticalSection(&server_cs);
360   return status;
361 }
362
363 /***********************************************************************
364  *             RpcServerUseProtseqEpA (RPCRT4.@)
365  */
366 RPC_STATUS WINAPI RpcServerUseProtseqEpA( LPSTR Protseq, UINT MaxCalls, LPSTR Endpoint, LPVOID SecurityDescriptor )
367 {
368   RPC_POLICY policy;
369   
370   TRACE( "(%s,%u,%s,%p)\n", Protseq, MaxCalls, Endpoint, SecurityDescriptor );
371   
372   /* This should provide the default behaviour */
373   policy.Length        = sizeof( policy );
374   policy.EndpointFlags = 0;
375   policy.NICFlags      = 0;
376   
377   return RpcServerUseProtseqEpExA( Protseq, MaxCalls, Endpoint, SecurityDescriptor, &policy );
378 }
379
380 /***********************************************************************
381  *             RpcServerUseProtseqEpW (RPCRT4.@)
382  */
383 RPC_STATUS WINAPI RpcServerUseProtseqEpW( LPWSTR Protseq, UINT MaxCalls, LPWSTR Endpoint, LPVOID SecurityDescriptor )
384 {
385   RPC_POLICY policy;
386   
387   TRACE( "(%s,%u,%s,%p)\n", debugstr_w( Protseq ), MaxCalls, debugstr_w( Endpoint ), SecurityDescriptor );
388   
389   /* This should provide the default behaviour */
390   policy.Length        = sizeof( policy );
391   policy.EndpointFlags = 0;
392   policy.NICFlags      = 0;
393   
394   return RpcServerUseProtseqEpExW( Protseq, MaxCalls, Endpoint, SecurityDescriptor, &policy );
395 }
396
397 /***********************************************************************
398  *             RpcServerUseProtseqEpExA (RPCRT4.@)
399  */
400 RPC_STATUS WINAPI RpcServerUseProtseqEpExA( LPSTR Protseq, UINT MaxCalls, LPSTR Endpoint, LPVOID SecurityDescriptor,
401                                             PRPC_POLICY lpPolicy )
402 {
403   RpcServerProtseq* ps;
404
405   TRACE("(%s,%u,%s,%p,{%u,%lu,%lu}): stub\n", debugstr_a( Protseq ), MaxCalls,
406        debugstr_a( Endpoint ), SecurityDescriptor,
407        lpPolicy->Length, lpPolicy->EndpointFlags, lpPolicy->NICFlags );
408
409   ps = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcServerProtseq));
410   ps->MaxCalls = MaxCalls;
411   ps->Protseq = RPCRT4_strdupA(Protseq);
412   ps->Endpoint = RPCRT4_strdupA(Endpoint);
413
414   return RPCRT4_use_protseq(ps);
415 }
416
417 /***********************************************************************
418  *             RpcServerUseProtseqEpExW (RPCRT4.@)
419  */
420 RPC_STATUS WINAPI RpcServerUseProtseqEpExW( LPWSTR Protseq, UINT MaxCalls, LPWSTR Endpoint, LPVOID SecurityDescriptor,
421                                             PRPC_POLICY lpPolicy )
422 {
423   RpcServerProtseq* ps;
424
425   TRACE("(%s,%u,%s,%p,{%u,%lu,%lu}): stub\n", debugstr_w( Protseq ), MaxCalls,
426        debugstr_w( Endpoint ), SecurityDescriptor,
427        lpPolicy->Length, lpPolicy->EndpointFlags, lpPolicy->NICFlags );
428
429   ps = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcServerProtseq));
430   ps->MaxCalls = MaxCalls;
431   /* FIXME: Did Ove have these next two as RPCRT4_strdupW for a reason? */
432   ps->Protseq = RPCRT4_strdupWtoA(Protseq);
433   ps->Endpoint = RPCRT4_strdupWtoA(Endpoint);
434
435   return RPCRT4_use_protseq(ps);
436 }
437
438 /***********************************************************************
439  *             RpcServerUseProtseqA (RPCRT4.@)
440  */
441 RPC_STATUS WINAPI RpcServerUseProtseqA(LPSTR Protseq, unsigned int MaxCalls, void *SecurityDescriptor)
442 {
443   FIXME("stub\n");
444   return RPC_S_OK;
445 }
446
447 /***********************************************************************
448  *             RpcServerUseProtseqW (RPCRT4.@)
449  */
450 RPC_STATUS WINAPI RpcServerUseProtseqW(LPWSTR Protseq, unsigned int MaxCalls, void *SecurityDescriptor)
451 {
452   FIXME("stub\n");
453   return RPC_S_OK;
454 }
455
456 /***********************************************************************
457  *             RpcServerRegisterIf (RPCRT4.@)
458  */
459 RPC_STATUS WINAPI RpcServerRegisterIf( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, RPC_MGR_EPV* MgrEpv )
460 {
461   TRACE("(%p,%s,%p)\n", IfSpec, debugstr_guid(MgrTypeUuid), MgrEpv);
462   return RpcServerRegisterIf2( IfSpec, MgrTypeUuid, MgrEpv, 0, RPC_C_LISTEN_MAX_CALLS_DEFAULT, (UINT)-1, NULL );
463 }
464
465 /***********************************************************************
466  *             RpcServerRegisterIfEx (RPCRT4.@)
467  */
468 RPC_STATUS WINAPI RpcServerRegisterIfEx( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, RPC_MGR_EPV* MgrEpv,
469                        UINT Flags, UINT MaxCalls, RPC_IF_CALLBACK_FN* IfCallbackFn )
470 {
471   TRACE("(%p,%s,%p,%u,%u,%p)\n", IfSpec, debugstr_guid(MgrTypeUuid), MgrEpv, Flags, MaxCalls, IfCallbackFn);
472   return RpcServerRegisterIf2( IfSpec, MgrTypeUuid, MgrEpv, Flags, MaxCalls, (UINT)-1, IfCallbackFn );
473 }
474
475 /***********************************************************************
476  *             RpcServerRegisterIf2 (RPCRT4.@)
477  */
478 RPC_STATUS WINAPI RpcServerRegisterIf2( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, RPC_MGR_EPV* MgrEpv,
479                       UINT Flags, UINT MaxCalls, UINT MaxRpcSize, RPC_IF_CALLBACK_FN* IfCallbackFn )
480 {
481   PRPC_SERVER_INTERFACE If = (PRPC_SERVER_INTERFACE)IfSpec;
482   RpcServerInterface* sif;
483   int i;
484
485   TRACE("(%p,%s,%p,%u,%u,%u,%p)\n", IfSpec, debugstr_guid(MgrTypeUuid), MgrEpv, Flags, MaxCalls,
486          MaxRpcSize, IfCallbackFn);
487   TRACE(" interface id: %s %d.%d\n", debugstr_guid(&If->InterfaceId.SyntaxGUID),
488                                      If->InterfaceId.SyntaxVersion.MajorVersion,
489                                      If->InterfaceId.SyntaxVersion.MinorVersion);
490   TRACE(" transfer syntax: %s %d.%d\n", debugstr_guid(&If->InterfaceId.SyntaxGUID),
491                                         If->InterfaceId.SyntaxVersion.MajorVersion,
492                                         If->InterfaceId.SyntaxVersion.MinorVersion);
493   TRACE(" dispatch table: %p\n", If->DispatchTable);
494   if (If->DispatchTable) {
495     TRACE("  dispatch table count: %d\n", If->DispatchTable->DispatchTableCount);
496     for (i=0; i<If->DispatchTable->DispatchTableCount; i++) {
497       TRACE("   entry %d: %p\n", i, If->DispatchTable->DispatchTable[i]);
498     }
499     TRACE("  reserved: %ld\n", If->DispatchTable->Reserved);
500   }
501   TRACE(" protseq endpoint count: %d\n", If->RpcProtseqEndpointCount);
502   TRACE(" default manager epv: %p\n", If->DefaultManagerEpv);
503   TRACE(" interpreter info: %p\n", If->InterpreterInfo);
504   TRACE(" flags: %08x\n", If->Flags);
505
506   sif = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcServerInterface));
507   sif->If           = If;
508   if (MgrTypeUuid)
509     memcpy(&sif->MgrTypeUuid, MgrTypeUuid, sizeof(UUID));
510   else
511     memset(&sif->MgrTypeUuid, 0, sizeof(UUID));
512   sif->MgrEpv       = MgrEpv;
513   sif->Flags        = Flags;
514   sif->MaxCalls     = MaxCalls;
515   sif->MaxRpcSize   = MaxRpcSize;
516   sif->IfCallbackFn = IfCallbackFn;
517
518   EnterCriticalSection(&server_cs);
519   sif->Next = ifs;
520   ifs = sif;
521   LeaveCriticalSection(&server_cs);
522
523   if (sif->Flags & RPC_IF_AUTOLISTEN) {
524     /* well, start listening, I think... */
525     RPCRT4_start_listen();
526   }
527
528   return RPC_S_OK;
529 }
530
531 /***********************************************************************
532  *             RpcServerRegisterAuthInfoA (RPCRT4.@)
533  */
534 RPC_STATUS WINAPI RpcServerRegisterAuthInfoA( LPSTR ServerPrincName, ULONG AuthnSvc, RPC_AUTH_KEY_RETRIEVAL_FN GetKeyFn,
535                             LPVOID Arg )
536 {
537   FIXME( "(%s,%lu,%p,%p): stub\n", ServerPrincName, AuthnSvc, GetKeyFn, Arg );
538   
539   return RPC_S_UNKNOWN_AUTHN_SERVICE; /* We don't know any authentication services */
540 }
541
542 /***********************************************************************
543  *             RpcServerRegisterAuthInfoW (RPCRT4.@)
544  */
545 RPC_STATUS WINAPI RpcServerRegisterAuthInfoW( LPWSTR ServerPrincName, ULONG AuthnSvc, RPC_AUTH_KEY_RETRIEVAL_FN GetKeyFn,
546                             LPVOID Arg )
547 {
548   FIXME( "(%s,%lu,%p,%p): stub\n", debugstr_w( ServerPrincName ), AuthnSvc, GetKeyFn, Arg );
549   
550   return RPC_S_UNKNOWN_AUTHN_SERVICE; /* We don't know any authentication services */
551 }
552
553 /***********************************************************************
554  *             RpcServerListen (RPCRT4.@)
555  */
556 RPC_STATUS WINAPI RpcServerListen( UINT MinimumCallThreads, UINT MaxCalls, UINT DontWait )
557 {
558   TRACE("(%u,%u,%u)\n", MinimumCallThreads, MaxCalls, DontWait);
559
560   if (std_listen)
561     return RPC_S_ALREADY_LISTENING;
562
563   if (!protseqs)
564     return RPC_S_NO_PROTSEQS_REGISTERED;
565
566   std_listen = TRUE;
567   RPCRT4_start_listen();
568
569   if (DontWait) return RPC_S_OK;
570
571   return RpcMgmtWaitServerListen();
572 }
573
574 /***********************************************************************
575  *             RpcMgmtServerWaitListen (RPCRT4.@)
576  */
577 RPC_STATUS WINAPI RpcMgmtWaitServerListen( void )
578 {
579   RPC_STATUS rslt = RPC_S_OK;
580
581   TRACE("\n");
582   if (!std_listen)
583     if ( (rslt = RpcServerListen(1, 0, TRUE)) != RPC_S_OK )
584       return rslt;
585   
586   while (std_listen) {
587     WaitForSingleObject(mgr_event, 1000);
588   }
589
590   return rslt;
591 }
592
593 /***********************************************************************
594  *             I_RpcServerStartListening (RPCRT4.@)
595  */
596 RPC_STATUS WINAPI I_RpcServerStartListening( void* hWnd )
597 {
598   FIXME( "(%p): stub\n", hWnd );
599
600   return RPC_S_OK;
601 }
602
603 /***********************************************************************
604  *             I_RpcServerStopListening (RPCRT4.@)
605  */
606 RPC_STATUS WINAPI I_RpcServerStopListening( void )
607 {
608   FIXME( "(): stub\n" );
609
610   return RPC_S_OK;
611 }
612
613 /***********************************************************************
614  *             I_RpcWindowProc (RPCRT4.@)
615  */
616 UINT WINAPI I_RpcWindowProc( void* hWnd, UINT Message, UINT wParam, ULONG lParam )
617 {
618   FIXME( "(%p,%08x,%08x,%08lx): stub\n", hWnd, Message, wParam, lParam );
619
620   return 0;
621 }