xref: /reactos/dll/win32/rpcrt4/rpcrt4_main.c (revision 1734f297)
1 /*
2  *  RPCRT4
3  *
4  * Copyright 2000 Huw D M Davies for CodeWeavers
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * WINE RPC TODO's (and a few TODONT's)
21  *
22  * - Statistics: we are supposed to be keeping various counters.  we aren't.
23  *
24  * - Async RPC: Unimplemented.
25  *
26  * - The NT "ports" API, aka LPC.  Greg claims this is on his radar.  Might (or
27  *   might not) enable users to get some kind of meaningful result out of
28  *   NT-based native rpcrt4's.  Commonly-used transport for self-to-self RPC's.
29  */
30 
31 #include <stdarg.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 
36 #include "ntstatus.h"
37 #define WIN32_NO_STATUS
38 #include "windef.h"
39 #include "winerror.h"
40 #include "winbase.h"
41 #include "winuser.h"
42 #include "winnt.h"
43 #include "wine/winternl.h"
44 #include "ntsecapi.h"
45 #include "iptypes.h"
46 #include "iphlpapi.h"
47 #include "rpc.h"
48 
49 #include "ole2.h"
50 #include "rpcndr.h"
51 #include "rpcproxy.h"
52 
53 #include "rpc_binding.h"
54 #include "rpc_server.h"
55 
56 #include "wine/debug.h"
57 
58 WINE_DEFAULT_DEBUG_CHANNEL(rpc);
59 
60 static UUID uuid_nil;
61 
62 static CRITICAL_SECTION uuid_cs;
63 static CRITICAL_SECTION_DEBUG critsect_debug =
64 {
65     0, 0, &uuid_cs,
66     { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
67       0, 0, { (DWORD_PTR)(__FILE__ ": uuid_cs") }
68 };
69 static CRITICAL_SECTION uuid_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
70 
71 static CRITICAL_SECTION threaddata_cs;
72 static CRITICAL_SECTION_DEBUG threaddata_cs_debug =
73 {
74     0, 0, &threaddata_cs,
75     { &threaddata_cs_debug.ProcessLocksList, &threaddata_cs_debug.ProcessLocksList },
76       0, 0, { (DWORD_PTR)(__FILE__ ": threaddata_cs") }
77 };
78 static CRITICAL_SECTION threaddata_cs = { &threaddata_cs_debug, -1, 0, 0, 0, 0 };
79 
80 static struct list threaddata_list = LIST_INIT(threaddata_list);
81 
82 struct context_handle_list
83 {
84     struct context_handle_list *next;
85     NDR_SCONTEXT context_handle;
86 };
87 
88 struct threaddata
89 {
90     struct list entry;
91     CRITICAL_SECTION cs;
92     DWORD thread_id;
93     RpcConnection *connection;
94     RpcBinding *server_binding;
95     struct context_handle_list *context_handle_list;
96 };
97 
98 /***********************************************************************
99  * DllMain
100  *
101  * PARAMS
102  *     hinstDLL    [I] handle to the DLL's instance
103  *     fdwReason   [I]
104  *     lpvReserved [I] reserved, must be NULL
105  *
106  * RETURNS
107  *     Success: TRUE
108  *     Failure: FALSE
109  */
110 
111 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
112 {
113     struct threaddata *tdata;
114 
115     switch (fdwReason) {
116     case DLL_PROCESS_ATTACH:
117         break;
118 
119     case DLL_THREAD_DETACH:
120         tdata = NtCurrentTeb()->ReservedForNtRpc;
121         if (tdata)
122         {
123             EnterCriticalSection(&threaddata_cs);
124             list_remove(&tdata->entry);
125             LeaveCriticalSection(&threaddata_cs);
126 
127             tdata->cs.DebugInfo->Spare[0] = 0;
128             DeleteCriticalSection(&tdata->cs);
129             if (tdata->connection)
130                 ERR("tdata->connection should be NULL but is still set to %p\n", tdata->connection);
131             if (tdata->server_binding)
132                 ERR("tdata->server_binding should be NULL but is still set to %p\n", tdata->server_binding);
133             HeapFree(GetProcessHeap(), 0, tdata);
134         }
135         break;
136 
137     case DLL_PROCESS_DETACH:
138         if (lpvReserved) break; /* do nothing if process is shutting down */
139         RPCRT4_destroy_all_protseqs();
140         RPCRT4_ServerFreeAllRegisteredAuthInfo();
141         DeleteCriticalSection(&uuid_cs);
142         DeleteCriticalSection(&threaddata_cs);
143         break;
144     }
145 
146     return TRUE;
147 }
148 
149 /*************************************************************************
150  *           RpcStringFreeA   [RPCRT4.@]
151  *
152  * Frees a character string allocated by the RPC run-time library.
153  *
154  * RETURNS
155  *
156  *  S_OK if successful.
157  */
158 RPC_STATUS WINAPI RpcStringFreeA(RPC_CSTR* String)
159 {
160   HeapFree( GetProcessHeap(), 0, *String);
161   if (String) *String = NULL;
162 
163   return RPC_S_OK;
164 }
165 
166 /*************************************************************************
167  *           RpcStringFreeW   [RPCRT4.@]
168  *
169  * Frees a character string allocated by the RPC run-time library.
170  *
171  * RETURNS
172  *
173  *  S_OK if successful.
174  */
175 RPC_STATUS WINAPI RpcStringFreeW(RPC_WSTR* String)
176 {
177   HeapFree( GetProcessHeap(), 0, *String);
178   if (String) *String = NULL;
179 
180   return RPC_S_OK;
181 }
182 
183 /*************************************************************************
184  *           RpcRaiseException   [RPCRT4.@]
185  *
186  * Raises an exception.
187  */
188 void DECLSPEC_NORETURN WINAPI RpcRaiseException(RPC_STATUS exception)
189 {
190   /* shouldn't return */
191   RaiseException(exception, 0, 0, NULL);
192   ERR("handler continued execution\n");
193   ExitProcess(1);
194 }
195 
196 /*************************************************************************
197  * UuidCompare [RPCRT4.@]
198  *
199  * PARAMS
200  *     UUID *Uuid1        [I] Uuid to compare
201  *     UUID *Uuid2        [I] Uuid to compare
202  *     RPC_STATUS *Status [O] returns RPC_S_OK
203  *
204  * RETURNS
205  *    -1  if Uuid1 is less than Uuid2
206  *     0  if Uuid1 and Uuid2 are equal
207  *     1  if Uuid1 is greater than Uuid2
208  */
209 int WINAPI UuidCompare(UUID *Uuid1, UUID *Uuid2, RPC_STATUS *Status)
210 {
211   int i;
212 
213   TRACE("(%s,%s)\n", debugstr_guid(Uuid1), debugstr_guid(Uuid2));
214 
215   *Status = RPC_S_OK;
216 
217   if (!Uuid1) Uuid1 = &uuid_nil;
218   if (!Uuid2) Uuid2 = &uuid_nil;
219 
220   if (Uuid1 == Uuid2) return 0;
221 
222   if (Uuid1->Data1 != Uuid2->Data1)
223     return Uuid1->Data1 < Uuid2->Data1 ? -1 : 1;
224 
225   if (Uuid1->Data2 != Uuid2->Data2)
226     return Uuid1->Data2 < Uuid2->Data2 ? -1 : 1;
227 
228   if (Uuid1->Data3 != Uuid2->Data3)
229     return Uuid1->Data3 < Uuid2->Data3 ? -1 : 1;
230 
231   for (i = 0; i < 8; i++) {
232     if (Uuid1->Data4[i] < Uuid2->Data4[i])
233       return -1;
234     if (Uuid1->Data4[i] > Uuid2->Data4[i])
235       return 1;
236   }
237 
238   return 0;
239 }
240 
241 /*************************************************************************
242  * UuidEqual [RPCRT4.@]
243  *
244  * PARAMS
245  *     UUID *Uuid1        [I] Uuid to compare
246  *     UUID *Uuid2        [I] Uuid to compare
247  *     RPC_STATUS *Status [O] returns RPC_S_OK
248  *
249  * RETURNS
250  *     TRUE/FALSE
251  */
252 int WINAPI UuidEqual(UUID *Uuid1, UUID *Uuid2, RPC_STATUS *Status)
253 {
254   TRACE("(%s,%s)\n", debugstr_guid(Uuid1), debugstr_guid(Uuid2));
255   return !UuidCompare(Uuid1, Uuid2, Status);
256 }
257 
258 /*************************************************************************
259  * UuidIsNil [RPCRT4.@]
260  *
261  * PARAMS
262  *     UUID *Uuid         [I] Uuid to compare
263  *     RPC_STATUS *Status [O] returns RPC_S_OK
264  *
265  * RETURNS
266  *     TRUE/FALSE
267  */
268 int WINAPI UuidIsNil(UUID *Uuid, RPC_STATUS *Status)
269 {
270   TRACE("(%s)\n", debugstr_guid(Uuid));
271   if (!Uuid) return TRUE;
272   return !UuidCompare(Uuid, &uuid_nil, Status);
273 }
274 
275  /*************************************************************************
276  * UuidCreateNil [RPCRT4.@]
277  *
278  * PARAMS
279  *     UUID *Uuid [O] returns a nil UUID
280  *
281  * RETURNS
282  *     RPC_S_OK
283  */
284 RPC_STATUS WINAPI UuidCreateNil(UUID *Uuid)
285 {
286   *Uuid = uuid_nil;
287   return RPC_S_OK;
288 }
289 
290 /*************************************************************************
291  *           UuidCreate   [RPCRT4.@]
292  *
293  * Creates a 128bit UUID.
294  *
295  * RETURNS
296  *
297  *  RPC_S_OK if successful.
298  *  RPC_S_UUID_LOCAL_ONLY if UUID is only locally unique.
299  *
300  * NOTES
301  *
302  *  Follows RFC 4122, section 4.4 (Algorithms for Creating a UUID from
303  *  Truly Random or Pseudo-Random Numbers)
304  */
305 RPC_STATUS WINAPI UuidCreate(UUID *Uuid)
306 {
307     RtlGenRandom(Uuid, sizeof(*Uuid));
308     /* Clear the version bits and set the version (4) */
309     Uuid->Data3 &= 0x0fff;
310     Uuid->Data3 |= (4 << 12);
311     /* Set the topmost bits of Data4 (clock_seq_hi_and_reserved) as
312      * specified in RFC 4122, section 4.4.
313      */
314     Uuid->Data4[0] &= 0x3f;
315     Uuid->Data4[0] |= 0x80;
316 
317     TRACE("%s\n", debugstr_guid(Uuid));
318 
319     return RPC_S_OK;
320 }
321 
322 /* Number of 100ns ticks per clock tick. To be safe, assume that the clock
323    resolution is at least 1000 * 100 * (1/1000000) = 1/10 of a second */
324 #define TICKS_PER_CLOCK_TICK 1000
325 #define SECSPERDAY  86400
326 #define TICKSPERSEC 10000000
327 /* UUID system time starts at October 15, 1582 */
328 #define SECS_15_OCT_1582_TO_1601  ((17 + 30 + 31 + 365 * 18 + 5) * SECSPERDAY)
329 #define TICKS_15_OCT_1582_TO_1601 ((ULONGLONG)SECS_15_OCT_1582_TO_1601 * TICKSPERSEC)
330 
331 static void RPC_UuidGetSystemTime(ULONGLONG *time)
332 {
333     FILETIME ft;
334 
335     GetSystemTimeAsFileTime(&ft);
336 
337     *time = ((ULONGLONG)ft.dwHighDateTime << 32) | ft.dwLowDateTime;
338     *time += TICKS_15_OCT_1582_TO_1601;
339 }
340 
341 /* Assume that a hardware address is at least 6 bytes long */
342 #define ADDRESS_BYTES_NEEDED 6
343 
344 static RPC_STATUS RPC_UuidGetNodeAddress(BYTE *address)
345 {
346     int i;
347     DWORD status = RPC_S_OK;
348 
349     ULONG buflen = sizeof(IP_ADAPTER_INFO);
350     PIP_ADAPTER_INFO adapter = HeapAlloc(GetProcessHeap(), 0, buflen);
351 
352     if (GetAdaptersInfo(adapter, &buflen) == ERROR_BUFFER_OVERFLOW) {
353         HeapFree(GetProcessHeap(), 0, adapter);
354         adapter = HeapAlloc(GetProcessHeap(), 0, buflen);
355     }
356 
357     if (GetAdaptersInfo(adapter, &buflen) == NO_ERROR) {
358         for (i = 0; i < ADDRESS_BYTES_NEEDED; i++) {
359             address[i] = adapter->Address[i];
360         }
361     }
362     /* We can't get a hardware address, just use random numbers.
363        Set the multicast bit to prevent conflicts with real cards. */
364     else {
365         RtlGenRandom(address, ADDRESS_BYTES_NEEDED);
366         address[0] |= 0x01;
367         status = RPC_S_UUID_LOCAL_ONLY;
368     }
369 
370     HeapFree(GetProcessHeap(), 0, adapter);
371     return status;
372 }
373 
374 /*************************************************************************
375  *           UuidCreateSequential   [RPCRT4.@]
376  *
377  * Creates a 128bit UUID.
378  *
379  * RETURNS
380  *
381  *  RPC_S_OK if successful.
382  *  RPC_S_UUID_LOCAL_ONLY if UUID is only locally unique.
383  *
384  *  FIXME: No compensation for changes across reloading
385  *         this dll or across reboots (e.g. clock going
386  *         backwards and swapped network cards). The RFC
387  *         suggests using NVRAM for storing persistent
388  *         values.
389  */
390 RPC_STATUS WINAPI UuidCreateSequential(UUID *Uuid)
391 {
392     static BOOL initialised;
393     static int count;
394 
395     ULONGLONG time;
396     static ULONGLONG timelast;
397     static WORD sequence;
398 
399     static DWORD status;
400     static BYTE address[MAX_ADAPTER_ADDRESS_LENGTH];
401 
402     EnterCriticalSection(&uuid_cs);
403 
404     if (!initialised) {
405         RPC_UuidGetSystemTime(&timelast);
406         count = TICKS_PER_CLOCK_TICK;
407 
408         sequence = ((rand() & 0xff) << 8) + (rand() & 0xff);
409         sequence &= 0x1fff;
410 
411         status = RPC_UuidGetNodeAddress(address);
412         initialised = TRUE;
413     }
414 
415     /* Generate time element of the UUID. Account for going faster
416        than our clock as well as the clock going backwards. */
417     while (1) {
418         RPC_UuidGetSystemTime(&time);
419         if (time > timelast) {
420             count = 0;
421             break;
422         }
423         if (time < timelast) {
424             sequence = (sequence + 1) & 0x1fff;
425             count = 0;
426             break;
427         }
428         if (count < TICKS_PER_CLOCK_TICK) {
429             count++;
430             break;
431         }
432     }
433 
434     timelast = time;
435     time += count;
436 
437     /* Pack the information into the UUID structure. */
438 
439     Uuid->Data1  = (ULONG)(time & 0xffffffff);
440     Uuid->Data2  = (unsigned short)((time >> 32) & 0xffff);
441     Uuid->Data3  = (unsigned short)((time >> 48) & 0x0fff);
442 
443     /* This is a version 1 UUID */
444     Uuid->Data3 |= (1 << 12);
445 
446     Uuid->Data4[0]  = sequence & 0xff;
447     Uuid->Data4[1]  = (sequence & 0x3f00) >> 8;
448     Uuid->Data4[1] |= 0x80;
449     memcpy(&Uuid->Data4[2], address, ADDRESS_BYTES_NEEDED);
450 
451     LeaveCriticalSection(&uuid_cs);
452 
453     TRACE("%s\n", debugstr_guid(Uuid));
454 
455     return status;
456 }
457 
458 /*************************************************************************
459  *           I_UuidCreate   [RPCRT4.@]
460  *
461  * See UuidCreateSequential()
462  */
463 RPC_STATUS WINAPI I_UuidCreate(UUID *Uuid)
464 {
465     return UuidCreateSequential(Uuid);
466 }
467 
468 /*************************************************************************
469  *           UuidHash   [RPCRT4.@]
470  *
471  * Generates a hash value for a given UUID
472  *
473  * Code based on FreeDCE implementation
474  *
475  */
476 unsigned short WINAPI UuidHash(UUID *uuid, RPC_STATUS *Status)
477 {
478   BYTE *data = (BYTE*)uuid;
479   short c0 = 0, c1 = 0, x, y;
480   unsigned int i;
481 
482   if (!uuid) data = (BYTE*)(uuid = &uuid_nil);
483 
484   TRACE("(%s)\n", debugstr_guid(uuid));
485 
486   for (i=0; i<sizeof(UUID); i++) {
487     c0 += data[i];
488     c1 += c0;
489   }
490 
491   x = -c1 % 255;
492   if (x < 0) x += 255;
493 
494   y = (c1 - c0) % 255;
495   if (y < 0) y += 255;
496 
497   *Status = RPC_S_OK;
498   return y*256 + x;
499 }
500 
501 /*************************************************************************
502  *           UuidToStringA   [RPCRT4.@]
503  *
504  * Converts a UUID to a string.
505  *
506  * UUID format is 8 hex digits, followed by a hyphen then three groups of
507  * 4 hex digits each followed by a hyphen and then 12 hex digits
508  *
509  * RETURNS
510  *
511  *  S_OK if successful.
512  *  S_OUT_OF_MEMORY if unsuccessful.
513  */
514 RPC_STATUS WINAPI UuidToStringA(UUID *Uuid, RPC_CSTR* StringUuid)
515 {
516   *StringUuid = HeapAlloc( GetProcessHeap(), 0, sizeof(char) * 37);
517 
518   if(!(*StringUuid))
519     return RPC_S_OUT_OF_MEMORY;
520 
521   if (!Uuid) Uuid = &uuid_nil;
522 
523   sprintf( (char*)*StringUuid, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
524                  Uuid->Data1, Uuid->Data2, Uuid->Data3,
525                  Uuid->Data4[0], Uuid->Data4[1], Uuid->Data4[2],
526                  Uuid->Data4[3], Uuid->Data4[4], Uuid->Data4[5],
527                  Uuid->Data4[6], Uuid->Data4[7] );
528 
529   return RPC_S_OK;
530 }
531 
532 /*************************************************************************
533  *           UuidToStringW   [RPCRT4.@]
534  *
535  * Converts a UUID to a string.
536  *
537  *  S_OK if successful.
538  *  S_OUT_OF_MEMORY if unsuccessful.
539  */
540 RPC_STATUS WINAPI UuidToStringW(UUID *Uuid, RPC_WSTR* StringUuid)
541 {
542   char buf[37];
543 
544   if (!Uuid) Uuid = &uuid_nil;
545 
546   sprintf(buf, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
547                Uuid->Data1, Uuid->Data2, Uuid->Data3,
548                Uuid->Data4[0], Uuid->Data4[1], Uuid->Data4[2],
549                Uuid->Data4[3], Uuid->Data4[4], Uuid->Data4[5],
550                Uuid->Data4[6], Uuid->Data4[7] );
551 
552   *StringUuid = RPCRT4_strdupAtoW(buf);
553 
554   if(!(*StringUuid))
555     return RPC_S_OUT_OF_MEMORY;
556 
557   return RPC_S_OK;
558 }
559 
560 static const BYTE hex2bin[] =
561 {
562     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,        /* 0x00 */
563     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,        /* 0x10 */
564     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,        /* 0x20 */
565     0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0,        /* 0x30 */
566     0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0,  /* 0x40 */
567     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,        /* 0x50 */
568     0,10,11,12,13,14,15                     /* 0x60 */
569 };
570 
571 /***********************************************************************
572  *		UuidFromStringA (RPCRT4.@)
573  */
574 RPC_STATUS WINAPI UuidFromStringA(RPC_CSTR s, UUID *uuid)
575 {
576     int i;
577 
578     if (!s) return UuidCreateNil( uuid );
579 
580     if (strlen((char*)s) != 36) return RPC_S_INVALID_STRING_UUID;
581 
582     if ((s[8]!='-') || (s[13]!='-') || (s[18]!='-') || (s[23]!='-'))
583         return RPC_S_INVALID_STRING_UUID;
584 
585     for (i=0; i<36; i++)
586     {
587         if ((i == 8)||(i == 13)||(i == 18)||(i == 23)) continue;
588         if (s[i] > 'f' || (!hex2bin[s[i]] && s[i] != '0')) return RPC_S_INVALID_STRING_UUID;
589     }
590 
591     /* in form XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX */
592 
593     uuid->Data1 = (hex2bin[s[0]] << 28 | hex2bin[s[1]] << 24 | hex2bin[s[2]] << 20 | hex2bin[s[3]] << 16 |
594                    hex2bin[s[4]] << 12 | hex2bin[s[5]]  << 8 | hex2bin[s[6]]  << 4 | hex2bin[s[7]]);
595     uuid->Data2 =  hex2bin[s[9]] << 12 | hex2bin[s[10]] << 8 | hex2bin[s[11]] << 4 | hex2bin[s[12]];
596     uuid->Data3 = hex2bin[s[14]] << 12 | hex2bin[s[15]] << 8 | hex2bin[s[16]] << 4 | hex2bin[s[17]];
597 
598     /* these are just sequential bytes */
599     uuid->Data4[0] = hex2bin[s[19]] << 4 | hex2bin[s[20]];
600     uuid->Data4[1] = hex2bin[s[21]] << 4 | hex2bin[s[22]];
601     uuid->Data4[2] = hex2bin[s[24]] << 4 | hex2bin[s[25]];
602     uuid->Data4[3] = hex2bin[s[26]] << 4 | hex2bin[s[27]];
603     uuid->Data4[4] = hex2bin[s[28]] << 4 | hex2bin[s[29]];
604     uuid->Data4[5] = hex2bin[s[30]] << 4 | hex2bin[s[31]];
605     uuid->Data4[6] = hex2bin[s[32]] << 4 | hex2bin[s[33]];
606     uuid->Data4[7] = hex2bin[s[34]] << 4 | hex2bin[s[35]];
607     return RPC_S_OK;
608 }
609 
610 
611 /***********************************************************************
612  *		UuidFromStringW (RPCRT4.@)
613  */
614 RPC_STATUS WINAPI UuidFromStringW(RPC_WSTR s, UUID *uuid)
615 {
616     int i;
617 
618     if (!s) return UuidCreateNil( uuid );
619 
620     if (lstrlenW(s) != 36) return RPC_S_INVALID_STRING_UUID;
621 
622     if ((s[8]!='-') || (s[13]!='-') || (s[18]!='-') || (s[23]!='-'))
623         return RPC_S_INVALID_STRING_UUID;
624 
625     for (i=0; i<36; i++)
626     {
627         if ((i == 8)||(i == 13)||(i == 18)||(i == 23)) continue;
628         if (s[i] > 'f' || (!hex2bin[s[i]] && s[i] != '0')) return RPC_S_INVALID_STRING_UUID;
629     }
630 
631     /* in form XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX */
632 
633     uuid->Data1 = (hex2bin[s[0]] << 28 | hex2bin[s[1]] << 24 | hex2bin[s[2]] << 20 | hex2bin[s[3]] << 16 |
634                    hex2bin[s[4]] << 12 | hex2bin[s[5]]  << 8 | hex2bin[s[6]]  << 4 | hex2bin[s[7]]);
635     uuid->Data2 =  hex2bin[s[9]] << 12 | hex2bin[s[10]] << 8 | hex2bin[s[11]] << 4 | hex2bin[s[12]];
636     uuid->Data3 = hex2bin[s[14]] << 12 | hex2bin[s[15]] << 8 | hex2bin[s[16]] << 4 | hex2bin[s[17]];
637 
638     /* these are just sequential bytes */
639     uuid->Data4[0] = hex2bin[s[19]] << 4 | hex2bin[s[20]];
640     uuid->Data4[1] = hex2bin[s[21]] << 4 | hex2bin[s[22]];
641     uuid->Data4[2] = hex2bin[s[24]] << 4 | hex2bin[s[25]];
642     uuid->Data4[3] = hex2bin[s[26]] << 4 | hex2bin[s[27]];
643     uuid->Data4[4] = hex2bin[s[28]] << 4 | hex2bin[s[29]];
644     uuid->Data4[5] = hex2bin[s[30]] << 4 | hex2bin[s[31]];
645     uuid->Data4[6] = hex2bin[s[32]] << 4 | hex2bin[s[33]];
646     uuid->Data4[7] = hex2bin[s[34]] << 4 | hex2bin[s[35]];
647     return RPC_S_OK;
648 }
649 
650 /***********************************************************************
651  *              DllRegisterServer (RPCRT4.@)
652  */
653 
654 HRESULT WINAPI DllRegisterServer( void )
655 {
656     FIXME( "(): stub\n" );
657     return S_OK;
658 }
659 
660 #define MAX_RPC_ERROR_TEXT 256
661 
662 /******************************************************************************
663  * DceErrorInqTextW   (rpcrt4.@)
664  *
665  * Notes
666  * 1. On passing a NULL pointer the code does bomb out.
667  * 2. The size of the required buffer is not defined in the documentation.
668  *    It appears to be 256.
669  * 3. The function is defined to return RPC_S_INVALID_ARG but I don't know
670  *    of any value for which it does.
671  * 4. The MSDN documentation currently declares that the second argument is
672  *    unsigned char *, even for the W version.  I don't believe it.
673  */
674 RPC_STATUS RPC_ENTRY DceErrorInqTextW (RPC_STATUS e, RPC_WSTR buffer)
675 {
676     DWORD count;
677     count = FormatMessageW (FORMAT_MESSAGE_FROM_SYSTEM |
678                 FORMAT_MESSAGE_IGNORE_INSERTS,
679                 NULL, e, 0, buffer, MAX_RPC_ERROR_TEXT, NULL);
680     if (!count)
681     {
682         count = FormatMessageW (FORMAT_MESSAGE_FROM_SYSTEM |
683                 FORMAT_MESSAGE_IGNORE_INSERTS,
684                 NULL, RPC_S_NOT_RPC_ERROR, 0, buffer, MAX_RPC_ERROR_TEXT, NULL);
685         if (!count)
686         {
687             ERR ("Failed to translate error\n");
688             return RPC_S_INVALID_ARG;
689         }
690     }
691     return RPC_S_OK;
692 }
693 
694 /******************************************************************************
695  * DceErrorInqTextA   (rpcrt4.@)
696  */
697 RPC_STATUS RPC_ENTRY DceErrorInqTextA (RPC_STATUS e, RPC_CSTR buffer)
698 {
699     RPC_STATUS status;
700     WCHAR bufferW [MAX_RPC_ERROR_TEXT];
701     if ((status = DceErrorInqTextW (e, bufferW)) == RPC_S_OK)
702     {
703         if (!WideCharToMultiByte(CP_ACP, 0, bufferW, -1, (LPSTR)buffer, MAX_RPC_ERROR_TEXT,
704                 NULL, NULL))
705         {
706             ERR ("Failed to translate error\n");
707             status = RPC_S_INVALID_ARG;
708         }
709     }
710     return status;
711 }
712 
713 /******************************************************************************
714  * I_RpcAllocate   (rpcrt4.@)
715  */
716 void * WINAPI I_RpcAllocate(unsigned int Size)
717 {
718     return HeapAlloc(GetProcessHeap(), 0, Size);
719 }
720 
721 /******************************************************************************
722  * I_RpcFree   (rpcrt4.@)
723  */
724 void WINAPI I_RpcFree(void *Object)
725 {
726     HeapFree(GetProcessHeap(), 0, Object);
727 }
728 
729 /******************************************************************************
730  * I_RpcMapWin32Status   (rpcrt4.@)
731  *
732  * Maps Win32 RPC error codes to NT statuses.
733  *
734  * PARAMS
735  *  status [I] Win32 RPC error code.
736  *
737  * RETURNS
738  *  Appropriate translation into an NT status code.
739  */
740 LONG WINAPI I_RpcMapWin32Status(RPC_STATUS status)
741 {
742     TRACE("(%d)\n", status);
743     switch (status)
744     {
745     case ERROR_ACCESS_DENIED: return STATUS_ACCESS_DENIED;
746     case ERROR_INVALID_HANDLE: return RPC_NT_SS_CONTEXT_MISMATCH;
747     case ERROR_OUTOFMEMORY: return STATUS_NO_MEMORY;
748     case ERROR_INVALID_PARAMETER: return STATUS_INVALID_PARAMETER;
749     case ERROR_INSUFFICIENT_BUFFER: return STATUS_BUFFER_TOO_SMALL;
750     case ERROR_MAX_THRDS_REACHED: return STATUS_NO_MEMORY;
751     case ERROR_NOACCESS: return STATUS_ACCESS_VIOLATION;
752     case ERROR_NOT_ENOUGH_SERVER_MEMORY: return STATUS_INSUFF_SERVER_RESOURCES;
753     case ERROR_WRONG_PASSWORD: return STATUS_WRONG_PASSWORD;
754     case ERROR_INVALID_LOGON_HOURS: return STATUS_INVALID_LOGON_HOURS;
755     case ERROR_PASSWORD_EXPIRED: return STATUS_PASSWORD_EXPIRED;
756     case ERROR_ACCOUNT_DISABLED: return STATUS_ACCOUNT_DISABLED;
757     case ERROR_INVALID_SECURITY_DESCR: return STATUS_INVALID_SECURITY_DESCR;
758     case RPC_S_INVALID_STRING_BINDING: return RPC_NT_INVALID_STRING_BINDING;
759     case RPC_S_WRONG_KIND_OF_BINDING: return RPC_NT_WRONG_KIND_OF_BINDING;
760     case RPC_S_INVALID_BINDING: return RPC_NT_INVALID_BINDING;
761     case RPC_S_PROTSEQ_NOT_SUPPORTED: return RPC_NT_PROTSEQ_NOT_SUPPORTED;
762     case RPC_S_INVALID_RPC_PROTSEQ: return RPC_NT_INVALID_RPC_PROTSEQ;
763     case RPC_S_INVALID_STRING_UUID: return RPC_NT_INVALID_STRING_UUID;
764     case RPC_S_INVALID_ENDPOINT_FORMAT: return RPC_NT_INVALID_ENDPOINT_FORMAT;
765     case RPC_S_INVALID_NET_ADDR: return RPC_NT_INVALID_NET_ADDR;
766     case RPC_S_NO_ENDPOINT_FOUND: return RPC_NT_NO_ENDPOINT_FOUND;
767     case RPC_S_INVALID_TIMEOUT: return RPC_NT_INVALID_TIMEOUT;
768     case RPC_S_OBJECT_NOT_FOUND: return RPC_NT_OBJECT_NOT_FOUND;
769     case RPC_S_ALREADY_REGISTERED: return RPC_NT_ALREADY_REGISTERED;
770     case RPC_S_TYPE_ALREADY_REGISTERED: return RPC_NT_TYPE_ALREADY_REGISTERED;
771     case RPC_S_ALREADY_LISTENING: return RPC_NT_ALREADY_LISTENING;
772     case RPC_S_NO_PROTSEQS_REGISTERED: return RPC_NT_NO_PROTSEQS_REGISTERED;
773     case RPC_S_NOT_LISTENING: return RPC_NT_NOT_LISTENING;
774     case RPC_S_UNKNOWN_MGR_TYPE: return RPC_NT_UNKNOWN_MGR_TYPE;
775     case RPC_S_UNKNOWN_IF: return RPC_NT_UNKNOWN_IF;
776     case RPC_S_NO_BINDINGS: return RPC_NT_NO_BINDINGS;
777     case RPC_S_NO_PROTSEQS: return RPC_NT_NO_PROTSEQS;
778     case RPC_S_CANT_CREATE_ENDPOINT: return RPC_NT_CANT_CREATE_ENDPOINT;
779     case RPC_S_OUT_OF_RESOURCES: return RPC_NT_OUT_OF_RESOURCES;
780     case RPC_S_SERVER_UNAVAILABLE: return RPC_NT_SERVER_UNAVAILABLE;
781     case RPC_S_SERVER_TOO_BUSY: return RPC_NT_SERVER_TOO_BUSY;
782     case RPC_S_INVALID_NETWORK_OPTIONS: return RPC_NT_INVALID_NETWORK_OPTIONS;
783     case RPC_S_NO_CALL_ACTIVE: return RPC_NT_NO_CALL_ACTIVE;
784     case RPC_S_CALL_FAILED: return RPC_NT_CALL_FAILED;
785     case RPC_S_CALL_FAILED_DNE: return RPC_NT_CALL_FAILED_DNE;
786     case RPC_S_PROTOCOL_ERROR: return RPC_NT_PROTOCOL_ERROR;
787     case RPC_S_UNSUPPORTED_TRANS_SYN: return RPC_NT_UNSUPPORTED_TRANS_SYN;
788     case RPC_S_UNSUPPORTED_TYPE: return RPC_NT_UNSUPPORTED_TYPE;
789     case RPC_S_INVALID_TAG: return RPC_NT_INVALID_TAG;
790     case RPC_S_INVALID_BOUND: return RPC_NT_INVALID_BOUND;
791     case RPC_S_NO_ENTRY_NAME: return RPC_NT_NO_ENTRY_NAME;
792     case RPC_S_INVALID_NAME_SYNTAX: return RPC_NT_INVALID_NAME_SYNTAX;
793     case RPC_S_UNSUPPORTED_NAME_SYNTAX: return RPC_NT_UNSUPPORTED_NAME_SYNTAX;
794     case RPC_S_UUID_NO_ADDRESS: return RPC_NT_UUID_NO_ADDRESS;
795     case RPC_S_DUPLICATE_ENDPOINT: return RPC_NT_DUPLICATE_ENDPOINT;
796     case RPC_S_UNKNOWN_AUTHN_TYPE: return RPC_NT_UNKNOWN_AUTHN_TYPE;
797     case RPC_S_MAX_CALLS_TOO_SMALL: return RPC_NT_MAX_CALLS_TOO_SMALL;
798     case RPC_S_STRING_TOO_LONG: return RPC_NT_STRING_TOO_LONG;
799     case RPC_S_PROTSEQ_NOT_FOUND: return RPC_NT_PROTSEQ_NOT_FOUND;
800     case RPC_S_PROCNUM_OUT_OF_RANGE: return RPC_NT_PROCNUM_OUT_OF_RANGE;
801     case RPC_S_BINDING_HAS_NO_AUTH: return RPC_NT_BINDING_HAS_NO_AUTH;
802     case RPC_S_UNKNOWN_AUTHN_SERVICE: return RPC_NT_UNKNOWN_AUTHN_SERVICE;
803     case RPC_S_UNKNOWN_AUTHN_LEVEL: return RPC_NT_UNKNOWN_AUTHN_LEVEL;
804     case RPC_S_INVALID_AUTH_IDENTITY: return RPC_NT_INVALID_AUTH_IDENTITY;
805     case RPC_S_UNKNOWN_AUTHZ_SERVICE: return RPC_NT_UNKNOWN_AUTHZ_SERVICE;
806     case EPT_S_INVALID_ENTRY: return EPT_NT_INVALID_ENTRY;
807     case EPT_S_CANT_PERFORM_OP: return EPT_NT_CANT_PERFORM_OP;
808     case EPT_S_NOT_REGISTERED: return EPT_NT_NOT_REGISTERED;
809     case EPT_S_CANT_CREATE: return EPT_NT_CANT_CREATE;
810     case RPC_S_NOTHING_TO_EXPORT: return RPC_NT_NOTHING_TO_EXPORT;
811     case RPC_S_INCOMPLETE_NAME: return RPC_NT_INCOMPLETE_NAME;
812     case RPC_S_INVALID_VERS_OPTION: return RPC_NT_INVALID_VERS_OPTION;
813     case RPC_S_NO_MORE_MEMBERS: return RPC_NT_NO_MORE_MEMBERS;
814     case RPC_S_NOT_ALL_OBJS_UNEXPORTED: return RPC_NT_NOT_ALL_OBJS_UNEXPORTED;
815     case RPC_S_INTERFACE_NOT_FOUND: return RPC_NT_INTERFACE_NOT_FOUND;
816     case RPC_S_ENTRY_ALREADY_EXISTS: return RPC_NT_ENTRY_ALREADY_EXISTS;
817     case RPC_S_ENTRY_NOT_FOUND: return RPC_NT_ENTRY_NOT_FOUND;
818     case RPC_S_NAME_SERVICE_UNAVAILABLE: return RPC_NT_NAME_SERVICE_UNAVAILABLE;
819     case RPC_S_INVALID_NAF_ID: return RPC_NT_INVALID_NAF_ID;
820     case RPC_S_CANNOT_SUPPORT: return RPC_NT_CANNOT_SUPPORT;
821     case RPC_S_NO_CONTEXT_AVAILABLE: return RPC_NT_NO_CONTEXT_AVAILABLE;
822     case RPC_S_INTERNAL_ERROR: return RPC_NT_INTERNAL_ERROR;
823     case RPC_S_ZERO_DIVIDE: return RPC_NT_ZERO_DIVIDE;
824     case RPC_S_ADDRESS_ERROR: return RPC_NT_ADDRESS_ERROR;
825     case RPC_S_FP_DIV_ZERO: return RPC_NT_FP_DIV_ZERO;
826     case RPC_S_FP_UNDERFLOW: return RPC_NT_FP_UNDERFLOW;
827     case RPC_S_FP_OVERFLOW: return RPC_NT_FP_OVERFLOW;
828     case RPC_S_CALL_IN_PROGRESS: return RPC_NT_CALL_IN_PROGRESS;
829     case RPC_S_NO_MORE_BINDINGS: return RPC_NT_NO_MORE_BINDINGS;
830     case RPC_S_CALL_CANCELLED: return RPC_NT_CALL_CANCELLED;
831     case RPC_S_INVALID_OBJECT: return RPC_NT_INVALID_OBJECT;
832     case RPC_S_INVALID_ASYNC_HANDLE: return RPC_NT_INVALID_ASYNC_HANDLE;
833     case RPC_S_INVALID_ASYNC_CALL: return RPC_NT_INVALID_ASYNC_CALL;
834     case RPC_S_GROUP_MEMBER_NOT_FOUND: return RPC_NT_GROUP_MEMBER_NOT_FOUND;
835     case RPC_X_NO_MORE_ENTRIES: return RPC_NT_NO_MORE_ENTRIES;
836     case RPC_X_SS_CHAR_TRANS_OPEN_FAIL: return RPC_NT_SS_CHAR_TRANS_OPEN_FAIL;
837     case RPC_X_SS_CHAR_TRANS_SHORT_FILE: return RPC_NT_SS_CHAR_TRANS_SHORT_FILE;
838     case RPC_X_SS_IN_NULL_CONTEXT: return RPC_NT_SS_IN_NULL_CONTEXT;
839     case RPC_X_SS_CONTEXT_DAMAGED: return RPC_NT_SS_CONTEXT_DAMAGED;
840     case RPC_X_SS_HANDLES_MISMATCH: return RPC_NT_SS_HANDLES_MISMATCH;
841     case RPC_X_SS_CANNOT_GET_CALL_HANDLE: return RPC_NT_SS_CANNOT_GET_CALL_HANDLE;
842     case RPC_X_NULL_REF_POINTER: return RPC_NT_NULL_REF_POINTER;
843     case RPC_X_ENUM_VALUE_OUT_OF_RANGE: return RPC_NT_ENUM_VALUE_OUT_OF_RANGE;
844     case RPC_X_BYTE_COUNT_TOO_SMALL: return RPC_NT_BYTE_COUNT_TOO_SMALL;
845     case RPC_X_BAD_STUB_DATA: return RPC_NT_BAD_STUB_DATA;
846     case RPC_X_PIPE_CLOSED: return RPC_NT_PIPE_CLOSED;
847     case RPC_X_PIPE_DISCIPLINE_ERROR: return RPC_NT_PIPE_DISCIPLINE_ERROR;
848     case RPC_X_PIPE_EMPTY: return RPC_NT_PIPE_EMPTY;
849     case ERROR_PASSWORD_MUST_CHANGE: return STATUS_PASSWORD_MUST_CHANGE;
850     case ERROR_ACCOUNT_LOCKED_OUT: return STATUS_ACCOUNT_LOCKED_OUT;
851     default: return status;
852     }
853 }
854 
855 /******************************************************************************
856  * RpcExceptionFilter     (rpcrt4.@)
857  * I_RpcExceptionFilter   (rpcrt4.@)
858  */
859 int WINAPI RpcExceptionFilter(ULONG ExceptionCode)
860 {
861     TRACE("0x%x\n", ExceptionCode);
862     switch (ExceptionCode)
863     {
864     case STATUS_DATATYPE_MISALIGNMENT:
865     case STATUS_BREAKPOINT:
866     case STATUS_ACCESS_VIOLATION:
867     case STATUS_ILLEGAL_INSTRUCTION:
868     case STATUS_PRIVILEGED_INSTRUCTION:
869     case STATUS_INSTRUCTION_MISALIGNMENT:
870     case STATUS_STACK_OVERFLOW:
871     case STATUS_POSSIBLE_DEADLOCK:
872         return EXCEPTION_CONTINUE_SEARCH;
873     default:
874         return EXCEPTION_EXECUTE_HANDLER;
875     }
876 }
877 
878 /******************************************************************************
879  * RpcErrorStartEnumeration   (rpcrt4.@)
880  */
881 RPC_STATUS RPC_ENTRY RpcErrorStartEnumeration(RPC_ERROR_ENUM_HANDLE* EnumHandle)
882 {
883     FIXME("(%p): stub\n", EnumHandle);
884     return RPC_S_ENTRY_NOT_FOUND;
885 }
886 
887 /******************************************************************************
888  * RpcErrorEndEnumeration   (rpcrt4.@)
889  */
890 RPC_STATUS RPC_ENTRY RpcErrorEndEnumeration(RPC_ERROR_ENUM_HANDLE* EnumHandle)
891 {
892     FIXME("(%p): stub\n", EnumHandle);
893     return RPC_S_OK;
894 }
895 
896 /******************************************************************************
897  * RpcErrorSaveErrorInfo   (rpcrt4.@)
898  */
899 RPC_STATUS RPC_ENTRY RpcErrorSaveErrorInfo(RPC_ERROR_ENUM_HANDLE *EnumHandle, void **ErrorBlob, SIZE_T *BlobSize)
900 {
901     FIXME("(%p %p %p): stub\n", EnumHandle, ErrorBlob, BlobSize);
902     return ERROR_CALL_NOT_IMPLEMENTED;
903 }
904 
905 /******************************************************************************
906  * RpcErrorLoadErrorInfo   (rpcrt4.@)
907  */
908 RPC_STATUS RPC_ENTRY RpcErrorLoadErrorInfo(void *ErrorBlob, SIZE_T BlobSize, RPC_ERROR_ENUM_HANDLE *EnumHandle)
909 {
910     FIXME("(%p %lu %p): stub\n", ErrorBlob, BlobSize, EnumHandle);
911     return ERROR_CALL_NOT_IMPLEMENTED;
912 }
913 
914 /******************************************************************************
915  * RpcErrorGetNextRecord   (rpcrt4.@)
916  */
917 RPC_STATUS RPC_ENTRY RpcErrorGetNextRecord(RPC_ERROR_ENUM_HANDLE *EnumHandle, BOOL CopyStrings, RPC_EXTENDED_ERROR_INFO *ErrorInfo)
918 {
919     FIXME("(%p %x %p): stub\n", EnumHandle, CopyStrings, ErrorInfo);
920     return RPC_S_ENTRY_NOT_FOUND;
921 }
922 
923 /******************************************************************************
924  * RpcMgmtSetCancelTimeout   (rpcrt4.@)
925  */
926 RPC_STATUS RPC_ENTRY RpcMgmtSetCancelTimeout(LONG Timeout)
927 {
928     FIXME("(%d): stub\n", Timeout);
929     return RPC_S_OK;
930 }
931 
932 static struct threaddata *get_or_create_threaddata(void)
933 {
934     struct threaddata *tdata = NtCurrentTeb()->ReservedForNtRpc;
935     if (!tdata)
936     {
937         tdata = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*tdata));
938         if (!tdata) return NULL;
939 
940         InitializeCriticalSection(&tdata->cs);
941         tdata->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": threaddata.cs");
942         tdata->thread_id = GetCurrentThreadId();
943 
944         EnterCriticalSection(&threaddata_cs);
945         list_add_tail(&threaddata_list, &tdata->entry);
946         LeaveCriticalSection(&threaddata_cs);
947 
948         NtCurrentTeb()->ReservedForNtRpc = tdata;
949         return tdata;
950     }
951     return tdata;
952 }
953 
954 void RPCRT4_SetThreadCurrentConnection(RpcConnection *Connection)
955 {
956     struct threaddata *tdata = get_or_create_threaddata();
957     if (!tdata) return;
958 
959     EnterCriticalSection(&tdata->cs);
960     tdata->connection = Connection;
961     LeaveCriticalSection(&tdata->cs);
962 }
963 
964 void RPCRT4_SetThreadCurrentCallHandle(RpcBinding *Binding)
965 {
966     struct threaddata *tdata = get_or_create_threaddata();
967     if (!tdata) return;
968 
969     tdata->server_binding = Binding;
970 }
971 
972 RpcBinding *RPCRT4_GetThreadCurrentCallHandle(void)
973 {
974     struct threaddata *tdata = get_or_create_threaddata();
975     if (!tdata) return NULL;
976 
977     return tdata->server_binding;
978 }
979 
980 void RPCRT4_PushThreadContextHandle(NDR_SCONTEXT SContext)
981 {
982     struct threaddata *tdata = get_or_create_threaddata();
983     struct context_handle_list *context_handle_list;
984 
985     if (!tdata) return;
986 
987     context_handle_list = HeapAlloc(GetProcessHeap(), 0, sizeof(*context_handle_list));
988     if (!context_handle_list) return;
989 
990     context_handle_list->context_handle = SContext;
991     context_handle_list->next = tdata->context_handle_list;
992     tdata->context_handle_list = context_handle_list;
993 }
994 
995 void RPCRT4_RemoveThreadContextHandle(NDR_SCONTEXT SContext)
996 {
997     struct threaddata *tdata = get_or_create_threaddata();
998     struct context_handle_list *current, *prev;
999 
1000     if (!tdata) return;
1001 
1002     for (current = tdata->context_handle_list, prev = NULL; current; prev = current, current = current->next)
1003     {
1004         if (current->context_handle == SContext)
1005         {
1006             if (prev)
1007                 prev->next = current->next;
1008             else
1009                 tdata->context_handle_list = current->next;
1010             HeapFree(GetProcessHeap(), 0, current);
1011             return;
1012         }
1013     }
1014 }
1015 
1016 NDR_SCONTEXT RPCRT4_PopThreadContextHandle(void)
1017 {
1018     struct threaddata *tdata = get_or_create_threaddata();
1019     struct context_handle_list *context_handle_list;
1020     NDR_SCONTEXT context_handle;
1021 
1022     if (!tdata) return NULL;
1023 
1024     context_handle_list = tdata->context_handle_list;
1025     if (!context_handle_list) return NULL;
1026     tdata->context_handle_list = context_handle_list->next;
1027 
1028     context_handle = context_handle_list->context_handle;
1029     HeapFree(GetProcessHeap(), 0, context_handle_list);
1030     return context_handle;
1031 }
1032 
1033 static RPC_STATUS rpc_cancel_thread(DWORD target_tid)
1034 {
1035     struct threaddata *tdata;
1036 
1037     EnterCriticalSection(&threaddata_cs);
1038     LIST_FOR_EACH_ENTRY(tdata, &threaddata_list, struct threaddata, entry)
1039         if (tdata->thread_id == target_tid)
1040         {
1041             EnterCriticalSection(&tdata->cs);
1042             if (tdata->connection) rpcrt4_conn_cancel_call(tdata->connection);
1043             LeaveCriticalSection(&tdata->cs);
1044             break;
1045         }
1046     LeaveCriticalSection(&threaddata_cs);
1047 
1048     return RPC_S_OK;
1049 }
1050 
1051 /******************************************************************************
1052  * RpcCancelThread   (rpcrt4.@)
1053  */
1054 RPC_STATUS RPC_ENTRY RpcCancelThread(void* ThreadHandle)
1055 {
1056     TRACE("(%p)\n", ThreadHandle);
1057     return RpcCancelThreadEx(ThreadHandle, 0);
1058 }
1059 
1060 /******************************************************************************
1061  * RpcCancelThreadEx   (rpcrt4.@)
1062  */
1063 RPC_STATUS RPC_ENTRY RpcCancelThreadEx(void* ThreadHandle, LONG Timeout)
1064 {
1065     DWORD target_tid;
1066 
1067     FIXME("(%p, %d)\n", ThreadHandle, Timeout);
1068 
1069     target_tid = GetThreadId(ThreadHandle);
1070     if (!target_tid)
1071         return RPC_S_INVALID_ARG;
1072 
1073     if (Timeout)
1074     {
1075         FIXME("(%p, %d)\n", ThreadHandle, Timeout);
1076         return RPC_S_OK;
1077     }
1078     else
1079         return rpc_cancel_thread(target_tid);
1080 }
1081