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