Fixed header dependencies to be fully compatible with the Windows
[wine] / dlls / rpcrt4 / rpc_binding.c
1 /*
2  * RPC binding 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 <stdarg.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <assert.h>
28
29 #include "windef.h"
30 #include "winbase.h"
31 #include "winnls.h"
32 #include "winerror.h"
33 #include "winreg.h"
34 #include "wine/unicode.h"
35
36 #include "rpc.h"
37
38 #include "wine/debug.h"
39
40 #include "rpc_binding.h"
41
42 WINE_DEFAULT_DEBUG_CHANNEL(ole);
43
44 static RpcConnection* conn_cache;
45
46 static CRITICAL_SECTION conn_cache_cs;
47 static CRITICAL_SECTION_DEBUG critsect_debug =
48 {
49     0, 0, &conn_cache_cs,
50     { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
51       0, 0, { 0, (DWORD)(__FILE__ ": conn_cache_cs") }
52 };
53 static CRITICAL_SECTION conn_cache_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
54
55 LPSTR RPCRT4_strndupA(LPSTR src, INT slen)
56 {
57   DWORD len;
58   LPSTR s;
59   if (!src) return NULL;
60   if (slen == -1) slen = strlen(src);
61   len = slen;
62   s = HeapAlloc(GetProcessHeap(), 0, len+1);
63   memcpy(s, src, len);
64   s[len] = 0;
65   return s;
66 }
67
68 LPSTR RPCRT4_strdupWtoA(LPWSTR src)
69 {
70   DWORD len;
71   LPSTR s;
72   if (!src) return NULL;
73   len = WideCharToMultiByte(CP_ACP, 0, src, -1, NULL, 0, NULL, NULL);
74   s = HeapAlloc(GetProcessHeap(), 0, len);
75   WideCharToMultiByte(CP_ACP, 0, src, -1, s, len, NULL, NULL);
76   return s;
77 }
78
79 LPWSTR RPCRT4_strdupAtoW(LPSTR src)
80 {
81   DWORD len;
82   LPWSTR s;
83   if (!src) return NULL;
84   len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0);
85   s = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
86   MultiByteToWideChar(CP_ACP, 0, src, -1, s, len);
87   return s;
88 }
89
90 LPWSTR RPCRT4_strndupW(LPWSTR src, INT slen)
91 {
92   DWORD len;
93   LPWSTR s;
94   if (!src) return NULL;
95   if (slen == -1) slen = strlenW(src);
96   len = slen;
97   s = HeapAlloc(GetProcessHeap(), 0, (len+1)*sizeof(WCHAR));
98   memcpy(s, src, len*sizeof(WCHAR));
99   s[len] = 0;
100   return s;
101 }
102
103 void RPCRT4_strfree(LPSTR src)
104 {
105   if (src) HeapFree(GetProcessHeap(), 0, src);
106 }
107
108 RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server, LPSTR Protseq, LPSTR NetworkAddr, LPSTR Endpoint, LPSTR NetworkOptions, RpcBinding* Binding)
109 {
110   RpcConnection* NewConnection;
111
112   NewConnection = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcConnection));
113   NewConnection->server = server;
114   NewConnection->Protseq = RPCRT4_strdupA(Protseq);
115   NewConnection->NetworkAddr = RPCRT4_strdupA(NetworkAddr);
116   NewConnection->Endpoint = RPCRT4_strdupA(Endpoint);
117   NewConnection->Used = Binding;
118
119   EnterCriticalSection(&conn_cache_cs);
120   NewConnection->Next = conn_cache;
121   conn_cache = NewConnection;
122   LeaveCriticalSection(&conn_cache_cs);
123
124   TRACE("connection: %p\n", NewConnection);
125   *Connection = NewConnection;
126
127   return RPC_S_OK;
128 }
129
130 RPC_STATUS RPCRT4_DestroyConnection(RpcConnection* Connection)
131 {
132   RpcConnection* PrevConnection;
133
134   TRACE("connection: %p\n", Connection);
135   if (Connection->Used) ERR("connection is still in use\n");
136
137   EnterCriticalSection(&conn_cache_cs);
138   PrevConnection = conn_cache;
139   while (PrevConnection && PrevConnection->Next != Connection)
140     PrevConnection = PrevConnection->Next;
141   if (PrevConnection) PrevConnection->Next = Connection->Next;
142   LeaveCriticalSection(&conn_cache_cs);
143
144   RPCRT4_CloseConnection(Connection);
145   RPCRT4_strfree(Connection->Endpoint);
146   RPCRT4_strfree(Connection->NetworkAddr);
147   RPCRT4_strfree(Connection->Protseq);
148   HeapFree(GetProcessHeap(), 0, Connection);
149   return RPC_S_OK;
150 }
151
152 RPC_STATUS RPCRT4_GetConnection(RpcConnection** Connection, BOOL server, LPSTR Protseq, LPSTR NetworkAddr, LPSTR Endpoint, LPSTR NetworkOptions, RpcBinding* Binding)
153 {
154   RpcConnection* NewConnection;
155
156   if (!server) {
157     EnterCriticalSection(&conn_cache_cs);
158     for (NewConnection = conn_cache; NewConnection; NewConnection = NewConnection->Next) {
159       if (NewConnection->Used) continue;
160       if (NewConnection->server != server) continue;
161       if (Protseq && strcmp(NewConnection->Protseq, Protseq)) continue;
162       if (NetworkAddr && strcmp(NewConnection->NetworkAddr, NetworkAddr)) continue;
163       if (Endpoint && strcmp(NewConnection->Endpoint, Endpoint)) continue;
164       /* this connection fits the bill */
165       NewConnection->Used = Binding;
166       break;
167     }
168     LeaveCriticalSection(&conn_cache_cs);
169     if (NewConnection) {
170       TRACE("cached connection: %p\n", NewConnection);
171       *Connection = NewConnection;
172       return RPC_S_OK;
173     }
174   }
175   return RPCRT4_CreateConnection(Connection, server, Protseq, NetworkAddr, Endpoint, NetworkOptions, Binding);
176 }
177
178 RPC_STATUS RPCRT4_ReleaseConnection(RpcConnection* Connection)
179 {
180   TRACE("connection: %p\n", Connection);
181   Connection->Used = NULL;
182   if (!Connection->server) {
183     /* cache the open connection for reuse later */
184     /* FIXME: we should probably clean the cache someday */
185     return RPC_S_OK;
186   }
187   return RPCRT4_DestroyConnection(Connection);
188 }
189
190 RPC_STATUS RPCRT4_OpenConnection(RpcConnection* Connection)
191 {
192   TRACE("(Connection == ^%p)\n", Connection);
193   if (!Connection->conn) {
194     if (Connection->server) { /* server */
195       /* protseq=ncalrpc: supposed to use NT LPC ports,
196        * but we'll implement it with named pipes for now */
197       if (strcmp(Connection->Protseq, "ncalrpc") == 0) {
198         static LPSTR prefix = "\\\\.\\pipe\\lrpc\\";
199         LPSTR pname;
200         pname = HeapAlloc(GetProcessHeap(), 0, strlen(prefix) + strlen(Connection->Endpoint) + 1);
201         strcat(strcpy(pname, prefix), Connection->Endpoint);
202         TRACE("listening on %s\n", pname);
203         Connection->conn = CreateNamedPipeA(pname, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
204                                          0, PIPE_UNLIMITED_INSTANCES, 0, 0, 5000, NULL);
205         HeapFree(GetProcessHeap(), 0, pname);
206         memset(&Connection->ovl, 0, sizeof(Connection->ovl));
207         Connection->ovl.hEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
208         if (!ConnectNamedPipe(Connection->conn, &Connection->ovl)) {
209           DWORD err = GetLastError();
210           if (err == ERROR_PIPE_CONNECTED) {
211             SetEvent(Connection->ovl.hEvent);
212             return RPC_S_OK;
213           }
214           return err;
215         }
216       }
217       /* protseq=ncacn_np: named pipes */
218       else if (strcmp(Connection->Protseq, "ncacn_np") == 0) {
219         static LPSTR prefix = "\\\\.";
220         LPSTR pname;
221         pname = HeapAlloc(GetProcessHeap(), 0, strlen(prefix) + strlen(Connection->Endpoint) + 1);
222         strcat(strcpy(pname, prefix), Connection->Endpoint);
223         TRACE("listening on %s\n", pname);
224         Connection->conn = CreateNamedPipeA(pname, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
225                                          0, PIPE_UNLIMITED_INSTANCES, 0, 0, 5000, NULL);
226         HeapFree(GetProcessHeap(), 0, pname);
227         memset(&Connection->ovl, 0, sizeof(Connection->ovl));
228         Connection->ovl.hEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
229         if (!ConnectNamedPipe(Connection->conn, &Connection->ovl)) {
230           DWORD err = GetLastError();
231           if (err == ERROR_PIPE_CONNECTED) {
232             SetEvent(Connection->ovl.hEvent);
233             return RPC_S_OK;
234           }
235           return err;
236         }
237       }
238       else {
239         ERR("protseq %s not supported\n", Connection->Protseq);
240         return RPC_S_PROTSEQ_NOT_SUPPORTED;
241       }
242     }
243     else { /* client */
244       /* protseq=ncalrpc: supposed to use NT LPC ports,
245        * but we'll implement it with named pipes for now */
246       if (strcmp(Connection->Protseq, "ncalrpc") == 0) {
247         static LPSTR prefix = "\\\\.\\pipe\\lrpc\\";
248         LPSTR pname;
249         HANDLE conn;
250         DWORD err;
251
252         pname = HeapAlloc(GetProcessHeap(), 0, strlen(prefix) + strlen(Connection->Endpoint) + 1);
253         strcat(strcpy(pname, prefix), Connection->Endpoint);
254         TRACE("connecting to %s\n", pname);
255         while (TRUE) {
256           if (WaitNamedPipeA(pname, NMPWAIT_WAIT_FOREVER)) {
257             conn = CreateFileA(pname, GENERIC_READ|GENERIC_WRITE, 0, NULL,
258                                OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
259             if (conn != INVALID_HANDLE_VALUE) break;
260             err = GetLastError();
261             if (err == ERROR_PIPE_BUSY) continue;
262             TRACE("connection failed, error=%lx\n", err);
263             HeapFree(GetProcessHeap(), 0, pname);
264             return err;
265           } else {
266             err = GetLastError();
267             TRACE("connection failed, error=%lx\n", err);
268             HeapFree(GetProcessHeap(), 0, pname);
269             return err;
270           }
271         }
272
273         /* success */
274         HeapFree(GetProcessHeap(), 0, pname);
275         memset(&Connection->ovl, 0, sizeof(Connection->ovl));
276         Connection->ovl.hEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
277         Connection->conn = conn;
278       }
279       /* protseq=ncacn_np: named pipes */
280       else if (strcmp(Connection->Protseq, "ncacn_np") == 0) {
281         static LPSTR prefix = "\\\\.";
282         LPSTR pname;
283         HANDLE conn;
284         DWORD err;
285
286         pname = HeapAlloc(GetProcessHeap(), 0, strlen(prefix) + strlen(Connection->Endpoint) + 1);
287         strcat(strcpy(pname, prefix), Connection->Endpoint);
288         TRACE("connecting to %s\n", pname);
289         conn = CreateFileA(pname, GENERIC_READ|GENERIC_WRITE, 0, NULL,
290                            OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
291         if (conn == INVALID_HANDLE_VALUE) {
292           err = GetLastError();
293           /* we don't need to handle ERROR_PIPE_BUSY here,
294            * the doc says that it is returned to the app */
295           TRACE("connection failed, error=%lx\n", err);
296           HeapFree(GetProcessHeap(), 0, pname);
297           return err;
298         }
299
300         /* success */
301         HeapFree(GetProcessHeap(), 0, pname);
302         memset(&Connection->ovl, 0, sizeof(Connection->ovl));
303         Connection->ovl.hEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
304         Connection->conn = conn;
305       } else {
306         ERR("protseq %s not supported\n", Connection->Protseq);
307         return RPC_S_PROTSEQ_NOT_SUPPORTED;
308       }
309     }
310   }
311   return RPC_S_OK;
312 }
313
314 RPC_STATUS RPCRT4_CloseConnection(RpcConnection* Connection)
315 {
316   TRACE("(Connection == ^%p)\n", Connection);
317   if (Connection->conn) {
318     CancelIo(Connection->conn);
319     CloseHandle(Connection->conn);
320     Connection->conn = 0;
321   }
322   if (Connection->ovl.hEvent) {
323     CloseHandle(Connection->ovl.hEvent);
324     Connection->ovl.hEvent = 0;
325   }
326   return RPC_S_OK;
327 }
328
329 RPC_STATUS RPCRT4_SpawnConnection(RpcConnection** Connection, RpcConnection* OldConnection)
330 {
331   RpcConnection* NewConnection;
332   RPC_STATUS err = RPCRT4_CreateConnection(&NewConnection, OldConnection->server, OldConnection->Protseq,
333                                            OldConnection->NetworkAddr, OldConnection->Endpoint, NULL, NULL);
334   if (err == RPC_S_OK) {
335     /* because of the way named pipes work, we'll transfer the connected pipe
336      * to the child, then reopen the server binding to continue listening */
337     NewConnection->conn = OldConnection->conn;
338     NewConnection->ovl = OldConnection->ovl;
339     OldConnection->conn = 0;
340     memset(&OldConnection->ovl, 0, sizeof(OldConnection->ovl));
341     *Connection = NewConnection;
342     RPCRT4_OpenConnection(OldConnection);
343   }
344   return err;
345 }
346
347 RPC_STATUS RPCRT4_AllocBinding(RpcBinding** Binding, BOOL server)
348 {
349   RpcBinding* NewBinding;
350
351   NewBinding = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcBinding));
352   NewBinding->refs = 1;
353   NewBinding->server = server;
354
355   *Binding = NewBinding;
356
357   return RPC_S_OK;
358 }
359
360 RPC_STATUS RPCRT4_CreateBindingA(RpcBinding** Binding, BOOL server, LPSTR Protseq)
361 {
362   RpcBinding* NewBinding;
363
364   RPCRT4_AllocBinding(&NewBinding, server);
365   NewBinding->Protseq = RPCRT4_strdupA(Protseq);
366
367   TRACE("binding: %p\n", NewBinding);
368   *Binding = NewBinding;
369
370   return RPC_S_OK;
371 }
372
373 RPC_STATUS RPCRT4_CreateBindingW(RpcBinding** Binding, BOOL server, LPWSTR Protseq)
374 {
375   RpcBinding* NewBinding;
376
377   RPCRT4_AllocBinding(&NewBinding, server);
378   NewBinding->Protseq = RPCRT4_strdupWtoA(Protseq);
379
380   TRACE("binding: %p\n", NewBinding);
381   *Binding = NewBinding;
382
383   return RPC_S_OK;
384 }
385
386 RPC_STATUS RPCRT4_CompleteBindingA(RpcBinding* Binding, LPSTR NetworkAddr,  LPSTR Endpoint,  LPSTR NetworkOptions)
387 {
388   TRACE("(RpcBinding == ^%p, NetworkAddr == \"%s\", EndPoint == \"%s\", NetworkOptions == \"%s\")\n", Binding,
389    debugstr_a(NetworkAddr), debugstr_a(Endpoint), debugstr_a(NetworkOptions));
390
391   RPCRT4_strfree(Binding->NetworkAddr);
392   Binding->NetworkAddr = RPCRT4_strdupA(NetworkAddr);
393   RPCRT4_strfree(Binding->Endpoint);
394   if (Endpoint) {
395     Binding->Endpoint = RPCRT4_strdupA(Endpoint);
396   } else {
397     Binding->Endpoint = RPCRT4_strdupA("");
398   }
399   if (!Binding->Endpoint) ERR("out of memory?\n");
400
401   return RPC_S_OK;
402 }
403
404 RPC_STATUS RPCRT4_CompleteBindingW(RpcBinding* Binding, LPWSTR NetworkAddr, LPWSTR Endpoint, LPWSTR NetworkOptions)
405 {
406   TRACE("(RpcBinding == ^%p, NetworkAddr == \"%s\", EndPoint == \"%s\", NetworkOptions == \"%s\")\n", Binding, 
407    debugstr_w(NetworkAddr), debugstr_w(Endpoint), debugstr_w(NetworkOptions));
408
409   RPCRT4_strfree(Binding->NetworkAddr);
410   Binding->NetworkAddr = RPCRT4_strdupWtoA(NetworkAddr);
411   RPCRT4_strfree(Binding->Endpoint);
412   if (Endpoint) {
413     Binding->Endpoint = RPCRT4_strdupWtoA(Endpoint);
414   } else {
415     Binding->Endpoint = RPCRT4_strdupA("");
416   }
417   if (!Binding->Endpoint) ERR("out of memory?\n");
418
419   return RPC_S_OK;
420 }
421
422 RPC_STATUS RPCRT4_ResolveBinding(RpcBinding* Binding, LPSTR Endpoint)
423 {
424   TRACE("(RpcBinding == ^%p, EndPoint == \"%s\"\n", Binding, Endpoint);
425
426   RPCRT4_strfree(Binding->Endpoint);
427   Binding->Endpoint = RPCRT4_strdupA(Endpoint);
428
429   return RPC_S_OK;
430 }
431
432 RPC_STATUS RPCRT4_SetBindingObject(RpcBinding* Binding, UUID* ObjectUuid)
433 {
434   TRACE("(*RpcBinding == ^%p, UUID == %s)\n", Binding, debugstr_guid(ObjectUuid)); 
435   if (ObjectUuid) memcpy(&Binding->ObjectUuid, ObjectUuid, sizeof(UUID));
436   else UuidCreateNil(&Binding->ObjectUuid);
437   return RPC_S_OK;
438 }
439
440 RPC_STATUS RPCRT4_MakeBinding(RpcBinding** Binding, RpcConnection* Connection)
441 {
442   RpcBinding* NewBinding;
443   TRACE("(*RpcBinding == ^%p, Connection == ^%p)\n", *Binding, Connection);
444
445   RPCRT4_AllocBinding(&NewBinding, Connection->server);
446   NewBinding->Protseq = RPCRT4_strdupA(Connection->Protseq);
447   NewBinding->NetworkAddr = RPCRT4_strdupA(Connection->NetworkAddr);
448   NewBinding->Endpoint = RPCRT4_strdupA(Connection->Endpoint);
449   NewBinding->FromConn = Connection;
450
451   TRACE("binding: %p\n", NewBinding);
452   *Binding = NewBinding;
453
454   return RPC_S_OK;
455 }
456
457 RPC_STATUS RPCRT4_ExportBinding(RpcBinding** Binding, RpcBinding* OldBinding)
458 {
459   InterlockedIncrement(&OldBinding->refs);
460   *Binding = OldBinding;
461   return RPC_S_OK;
462 }
463
464 RPC_STATUS RPCRT4_DestroyBinding(RpcBinding* Binding)
465 {
466   if (InterlockedDecrement(&Binding->refs))
467     return RPC_S_OK;
468
469   TRACE("binding: %p\n", Binding);
470   /* FIXME: release connections */
471   RPCRT4_strfree(Binding->Endpoint);
472   RPCRT4_strfree(Binding->NetworkAddr);
473   RPCRT4_strfree(Binding->Protseq);
474   HeapFree(GetProcessHeap(), 0, Binding);
475   return RPC_S_OK;
476 }
477
478 RPC_STATUS RPCRT4_OpenBinding(RpcBinding* Binding, RpcConnection** Connection)
479 {
480   RpcConnection* NewConnection;
481   TRACE("(Binding == ^%p)\n", Binding);
482   if (Binding->FromConn) {
483     *Connection = Binding->FromConn;
484     return RPC_S_OK;
485   }
486
487   RPCRT4_GetConnection(&NewConnection, Binding->server, Binding->Protseq, Binding->NetworkAddr, Binding->Endpoint, NULL, Binding);
488   *Connection = NewConnection;
489   return RPCRT4_OpenConnection(NewConnection);
490 }
491
492 RPC_STATUS RPCRT4_CloseBinding(RpcBinding* Binding, RpcConnection* Connection)
493 {
494   TRACE("(Binding == ^%p)\n", Binding);
495   if (!Connection) return RPC_S_OK;
496   if (Binding->FromConn == Connection) return RPC_S_OK;
497   return RPCRT4_ReleaseConnection(Connection);
498 }
499
500 /* utility functions for string composing and parsing */
501 static unsigned RPCRT4_strcopyA(LPSTR data, LPCSTR src)
502 {
503   unsigned len = strlen(src);
504   memcpy(data, src, len*sizeof(CHAR));
505   return len;
506 }
507
508 static unsigned RPCRT4_strcopyW(LPWSTR data, LPCWSTR src)
509 {
510   unsigned len = strlenW(src);
511   memcpy(data, src, len*sizeof(WCHAR));
512   return len;
513 }
514
515 static LPSTR RPCRT4_strconcatA(LPSTR dst, LPCSTR src)
516 {
517   DWORD len = strlen(dst), slen = strlen(src);
518   LPSTR ndst = HeapReAlloc(GetProcessHeap(), 0, dst, (len+slen+2)*sizeof(CHAR));
519   if (!ndst) HeapFree(GetProcessHeap(), 0, dst);
520   ndst[len] = ',';
521   memcpy(ndst+len+1, src, slen*sizeof(CHAR));
522   ndst[len+slen+1] = 0;
523   return ndst;
524 }
525
526 static LPWSTR RPCRT4_strconcatW(LPWSTR dst, LPCWSTR src)
527 {
528   DWORD len = strlenW(dst), slen = strlenW(src);
529   LPWSTR ndst = HeapReAlloc(GetProcessHeap(), 0, dst, (len+slen+2)*sizeof(WCHAR));
530   if (!ndst) HeapFree(GetProcessHeap(), 0, dst);
531   ndst[len] = ',';
532   memcpy(ndst+len+1, src, slen*sizeof(WCHAR));
533   ndst[len+slen+1] = 0;
534   return ndst;
535 }
536
537
538 /***********************************************************************
539  *             RpcStringBindingComposeA (RPCRT4.@)
540  */
541 RPC_STATUS WINAPI RpcStringBindingComposeA( LPSTR ObjUuid, LPSTR Protseq,
542                                            LPSTR NetworkAddr, LPSTR Endpoint,
543                                            LPSTR Options, LPSTR* StringBinding )
544 {
545   DWORD len = 1;
546   LPSTR data;
547
548   TRACE( "(%s,%s,%s,%s,%s,%p)\n",
549         debugstr_a( ObjUuid ), debugstr_a( Protseq ),
550         debugstr_a( NetworkAddr ), debugstr_a( Endpoint ),
551         debugstr_a( Options ), StringBinding );
552
553   if (ObjUuid && *ObjUuid) len += strlen(ObjUuid) + 1;
554   if (Protseq && *Protseq) len += strlen(Protseq) + 1;
555   if (NetworkAddr && *NetworkAddr) len += strlen(NetworkAddr);
556   if (Endpoint && *Endpoint) len += strlen(Endpoint) + 2;
557   if (Options && *Options) len += strlen(Options) + 2;
558
559   data = HeapAlloc(GetProcessHeap(), 0, len);
560   *StringBinding = data;
561
562   if (ObjUuid && *ObjUuid) {
563     data += RPCRT4_strcopyA(data, ObjUuid);
564     *data++ = '@';
565   }
566   if (Protseq && *Protseq) {
567     data += RPCRT4_strcopyA(data, Protseq);
568     *data++ = ':';
569   }
570   if (NetworkAddr && *NetworkAddr)
571     data += RPCRT4_strcopyA(data, NetworkAddr);
572
573   if ((Endpoint && *Endpoint) ||
574       (Options && *Options)) {
575     *data++ = '[';
576     if (Endpoint && *Endpoint) {
577       data += RPCRT4_strcopyA(data, Endpoint);
578       if (Options && *Options) *data++ = ',';
579     }
580     if (Options && *Options) {
581       data += RPCRT4_strcopyA(data, Options);
582     }
583     *data++ = ']';
584   }
585   *data = 0;
586
587   return RPC_S_OK;
588 }
589
590 /***********************************************************************
591  *             RpcStringBindingComposeW (RPCRT4.@)
592  */
593 RPC_STATUS WINAPI RpcStringBindingComposeW( LPWSTR ObjUuid, LPWSTR Protseq,
594                                             LPWSTR NetworkAddr, LPWSTR Endpoint,
595                                             LPWSTR Options, LPWSTR* StringBinding )
596 {
597   DWORD len = 1;
598   LPWSTR data;
599
600   TRACE("(%s,%s,%s,%s,%s,%p)\n",
601        debugstr_w( ObjUuid ), debugstr_w( Protseq ),
602        debugstr_w( NetworkAddr ), debugstr_w( Endpoint ),
603        debugstr_w( Options ), StringBinding);
604
605   if (ObjUuid && *ObjUuid) len += strlenW(ObjUuid) + 1;
606   if (Protseq && *Protseq) len += strlenW(Protseq) + 1;
607   if (NetworkAddr && *NetworkAddr) len += strlenW(NetworkAddr);
608   if (Endpoint && *Endpoint) len += strlenW(Endpoint) + 2;
609   if (Options && *Options) len += strlenW(Options) + 2;
610
611   data = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
612   *StringBinding = data;
613
614   if (ObjUuid && *ObjUuid) {
615     data += RPCRT4_strcopyW(data, ObjUuid);
616     *data++ = '@';
617   }
618   if (Protseq && *Protseq) {
619     data += RPCRT4_strcopyW(data, Protseq);
620     *data++ = ':';
621   }
622   if (NetworkAddr && *NetworkAddr) {
623     data += RPCRT4_strcopyW(data, NetworkAddr);
624   }
625   if ((Endpoint && *Endpoint) ||
626       (Options && *Options)) {
627     *data++ = '[';
628     if (Endpoint && *Endpoint) {
629       data += RPCRT4_strcopyW(data, Endpoint);
630       if (Options && *Options) *data++ = ',';
631     }
632     if (Options && *Options) {
633       data += RPCRT4_strcopyW(data, Options);
634     }
635     *data++ = ']';
636   }
637   *data = 0;
638
639   return RPC_S_OK;
640 }
641
642
643 /***********************************************************************
644  *             RpcStringBindingParseA (RPCRT4.@)
645  */
646 RPC_STATUS WINAPI RpcStringBindingParseA( LPSTR StringBinding, LPSTR *ObjUuid,
647                                           LPSTR *Protseq, LPSTR *NetworkAddr,
648                                           LPSTR *Endpoint, LPSTR *Options)
649 {
650   CHAR *data, *next;
651   static const char ep_opt[] = "endpoint=";
652
653   TRACE("(%s,%p,%p,%p,%p,%p)\n", debugstr_a(StringBinding),
654        ObjUuid, Protseq, NetworkAddr, Endpoint, Options);
655
656   if (ObjUuid) *ObjUuid = NULL;
657   if (Protseq) *Protseq = NULL;
658   if (NetworkAddr) *NetworkAddr = NULL;
659   if (Endpoint) *Endpoint = NULL;
660   if (Options) *Options = NULL;
661
662   data = StringBinding;
663
664   next = strchr(data, '@');
665   if (next) {
666     if (ObjUuid) *ObjUuid = RPCRT4_strndupA(data, next - data);
667     data = next+1;
668   }
669
670   next = strchr(data, ':');
671   if (next) {
672     if (Protseq) *Protseq = RPCRT4_strndupA(data, next - data);
673     data = next+1;
674   }
675
676   next = strchr(data, '[');
677   if (next) {
678     CHAR *close, *opt;
679
680     if (NetworkAddr) *NetworkAddr = RPCRT4_strndupA(data, next - data);
681     data = next+1;
682     close = strchr(data, ']');
683     if (!close) goto fail;
684
685     /* tokenize options */
686     while (data < close) {
687       next = strchr(data, ',');
688       if (!next || next > close) next = close;
689       /* FIXME: this is kind of inefficient */
690       opt = RPCRT4_strndupA(data, next - data);
691       data = next+1;
692
693       /* parse option */
694       next = strchr(opt, '=');
695       if (!next) {
696         /* not an option, must be an endpoint */
697         if (*Endpoint) goto fail;
698         *Endpoint = opt;
699       } else {
700         if (strncmp(opt, ep_opt, strlen(ep_opt)) == 0) {
701           /* endpoint option */
702           if (*Endpoint) goto fail;
703           *Endpoint = RPCRT4_strdupA(next+1);
704           HeapFree(GetProcessHeap(), 0, opt);
705         } else {
706           /* network option */
707           if (*Options) {
708             /* FIXME: this is kind of inefficient */
709             *Options = RPCRT4_strconcatA(*Options, opt);
710             HeapFree(GetProcessHeap(), 0, opt);
711           } else 
712             *Options = opt;
713         }
714       }
715     }
716
717     data = close+1;
718     if (*data) goto fail;
719   }
720   else if (NetworkAddr) 
721     *NetworkAddr = RPCRT4_strdupA(data);
722
723   return RPC_S_OK;
724
725 fail:
726   if (ObjUuid) RpcStringFreeA((unsigned char**)ObjUuid);
727   if (Protseq) RpcStringFreeA((unsigned char**)Protseq);
728   if (NetworkAddr) RpcStringFreeA((unsigned char**)NetworkAddr);
729   if (Endpoint) RpcStringFreeA((unsigned char**)Endpoint);
730   if (Options) RpcStringFreeA((unsigned char**)Options);
731   return RPC_S_INVALID_STRING_BINDING;
732 }
733
734 /***********************************************************************
735  *             RpcStringBindingParseW (RPCRT4.@)
736  */
737 RPC_STATUS WINAPI RpcStringBindingParseW( LPWSTR StringBinding, LPWSTR *ObjUuid,
738                                           LPWSTR *Protseq, LPWSTR *NetworkAddr,
739                                           LPWSTR *Endpoint, LPWSTR *Options)
740 {
741   WCHAR *data, *next;
742   static const WCHAR ep_opt[] = {'e','n','d','p','o','i','n','t','=',0};
743
744   TRACE("(%s,%p,%p,%p,%p,%p)\n", debugstr_w(StringBinding),
745        ObjUuid, Protseq, NetworkAddr, Endpoint, Options);
746
747   if (ObjUuid) *ObjUuid = NULL;
748   if (Protseq) *Protseq = NULL;
749   if (NetworkAddr) *NetworkAddr = NULL;
750   if (Endpoint) *Endpoint = NULL;
751   if (Options) *Options = NULL;
752
753   data = StringBinding;
754
755   next = strchrW(data, '@');
756   if (next) {
757     if (ObjUuid) *ObjUuid = RPCRT4_strndupW(data, next - data);
758     data = next+1;
759   }
760
761   next = strchrW(data, ':');
762   if (next) {
763     if (Protseq) *Protseq = RPCRT4_strndupW(data, next - data);
764     data = next+1;
765   }
766
767   next = strchrW(data, '[');
768   if (next) {
769     WCHAR *close, *opt;
770
771     if (NetworkAddr) *NetworkAddr = RPCRT4_strndupW(data, next - data);
772     data = next+1;
773     close = strchrW(data, ']');
774     if (!close) goto fail;
775
776     /* tokenize options */
777     while (data < close) {
778       next = strchrW(data, ',');
779       if (!next || next > close) next = close;
780       /* FIXME: this is kind of inefficient */
781       opt = RPCRT4_strndupW(data, next - data);
782       data = next+1;
783
784       /* parse option */
785       next = strchrW(opt, '=');
786       if (!next) {
787         /* not an option, must be an endpoint */
788         if (*Endpoint) goto fail;
789         *Endpoint = opt;
790       } else {
791         if (strncmpW(opt, ep_opt, strlenW(ep_opt)) == 0) {
792           /* endpoint option */
793           if (*Endpoint) goto fail;
794           *Endpoint = RPCRT4_strdupW(next+1);
795           HeapFree(GetProcessHeap(), 0, opt);
796         } else {
797           /* network option */
798           if (*Options) {
799             /* FIXME: this is kind of inefficient */
800             *Options = RPCRT4_strconcatW(*Options, opt);
801             HeapFree(GetProcessHeap(), 0, opt);
802           } else 
803             *Options = opt;
804         }
805       }
806     }
807
808     data = close+1;
809     if (*data) goto fail;
810   } else if (NetworkAddr) 
811     *NetworkAddr = RPCRT4_strdupW(data);
812
813   return RPC_S_OK;
814
815 fail:
816   if (ObjUuid) RpcStringFreeW(ObjUuid);
817   if (Protseq) RpcStringFreeW(Protseq);
818   if (NetworkAddr) RpcStringFreeW(NetworkAddr);
819   if (Endpoint) RpcStringFreeW(Endpoint);
820   if (Options) RpcStringFreeW(Options);
821   return RPC_S_INVALID_STRING_BINDING;
822 }
823
824 /***********************************************************************
825  *             RpcBindingFree (RPCRT4.@)
826  */
827 RPC_STATUS WINAPI RpcBindingFree( RPC_BINDING_HANDLE* Binding )
828 {
829   RPC_STATUS status;
830   TRACE("(%p) = %p\n", Binding, *Binding);
831   status = RPCRT4_DestroyBinding(*Binding);
832   if (status == RPC_S_OK) *Binding = 0;
833   return status;
834 }
835   
836 /***********************************************************************
837  *             RpcBindingVectorFree (RPCRT4.@)
838  */
839 RPC_STATUS WINAPI RpcBindingVectorFree( RPC_BINDING_VECTOR** BindingVector )
840 {
841   RPC_STATUS status;
842   unsigned long c;
843
844   TRACE("(%p)\n", BindingVector);
845   for (c=0; c<(*BindingVector)->Count; c++) {
846     status = RpcBindingFree(&(*BindingVector)->BindingH[c]);
847   }
848   HeapFree(GetProcessHeap(), 0, *BindingVector);
849   *BindingVector = NULL;
850   return RPC_S_OK;
851 }
852   
853 /***********************************************************************
854  *             RpcBindingInqObject (RPCRT4.@)
855  */
856 RPC_STATUS WINAPI RpcBindingInqObject( RPC_BINDING_HANDLE Binding, UUID* ObjectUuid )
857 {
858   RpcBinding* bind = (RpcBinding*)Binding;
859
860   TRACE("(%p,%p) = %s\n", Binding, ObjectUuid, debugstr_guid(&bind->ObjectUuid));
861   memcpy(ObjectUuid, &bind->ObjectUuid, sizeof(UUID));
862   return RPC_S_OK;
863 }
864   
865 /***********************************************************************
866  *             RpcBindingSetObject (RPCRT4.@)
867  */
868 RPC_STATUS WINAPI RpcBindingSetObject( RPC_BINDING_HANDLE Binding, UUID* ObjectUuid )
869 {
870   RpcBinding* bind = (RpcBinding*)Binding;
871
872   TRACE("(%p,%s)\n", Binding, debugstr_guid(ObjectUuid));
873   if (bind->server) return RPC_S_WRONG_KIND_OF_BINDING;
874   return RPCRT4_SetBindingObject(Binding, ObjectUuid);
875 }
876
877 /***********************************************************************
878  *             RpcBindingFromStringBindingA (RPCRT4.@)
879  */
880 RPC_STATUS WINAPI RpcBindingFromStringBindingA( LPSTR StringBinding, RPC_BINDING_HANDLE* Binding )
881 {
882   RPC_STATUS ret;
883   RpcBinding* bind = NULL;
884   LPSTR ObjectUuid, Protseq, NetworkAddr, Endpoint, Options;
885   UUID Uuid;
886
887   TRACE("(%s,%p)\n", debugstr_a(StringBinding), Binding);
888
889   ret = RpcStringBindingParseA(StringBinding, &ObjectUuid, &Protseq,
890                               &NetworkAddr, &Endpoint, &Options);
891   if (ret != RPC_S_OK) return ret;
892
893   ret = UuidFromStringA(ObjectUuid, &Uuid);
894
895   if (ret == RPC_S_OK)
896     ret = RPCRT4_CreateBindingA(&bind, FALSE, Protseq);
897   if (ret == RPC_S_OK)
898     ret = RPCRT4_SetBindingObject(bind, &Uuid);
899   if (ret == RPC_S_OK)
900     ret = RPCRT4_CompleteBindingA(bind, NetworkAddr, Endpoint, Options);
901
902   RpcStringFreeA((unsigned char**)&Options);
903   RpcStringFreeA((unsigned char**)&Endpoint);
904   RpcStringFreeA((unsigned char**)&NetworkAddr);
905   RpcStringFreeA((unsigned char**)&Protseq);
906   RpcStringFreeA((unsigned char**)&ObjectUuid);
907
908   if (ret == RPC_S_OK) 
909     *Binding = (RPC_BINDING_HANDLE)bind;
910   else 
911     RPCRT4_DestroyBinding(bind);
912
913   return ret;
914 }
915
916 /***********************************************************************
917  *             RpcBindingFromStringBindingW (RPCRT4.@)
918  */
919 RPC_STATUS WINAPI RpcBindingFromStringBindingW( LPWSTR StringBinding, RPC_BINDING_HANDLE* Binding )
920 {
921   RPC_STATUS ret;
922   RpcBinding* bind = NULL;
923   LPWSTR ObjectUuid, Protseq, NetworkAddr, Endpoint, Options;
924   UUID Uuid;
925
926   TRACE("(%s,%p)\n", debugstr_w(StringBinding), Binding);
927
928   ret = RpcStringBindingParseW(StringBinding, &ObjectUuid, &Protseq,
929                               &NetworkAddr, &Endpoint, &Options);
930   if (ret != RPC_S_OK) return ret;
931
932   ret = UuidFromStringW(ObjectUuid, &Uuid);
933
934   if (ret == RPC_S_OK)
935     ret = RPCRT4_CreateBindingW(&bind, FALSE, Protseq);
936   if (ret == RPC_S_OK)
937     ret = RPCRT4_SetBindingObject(bind, &Uuid);
938   if (ret == RPC_S_OK)
939     ret = RPCRT4_CompleteBindingW(bind, NetworkAddr, Endpoint, Options);
940
941   RpcStringFreeW(&Options);
942   RpcStringFreeW(&Endpoint);
943   RpcStringFreeW(&NetworkAddr);
944   RpcStringFreeW(&Protseq);
945   RpcStringFreeW(&ObjectUuid);
946
947   if (ret == RPC_S_OK)
948     *Binding = (RPC_BINDING_HANDLE)bind;
949   else
950     RPCRT4_DestroyBinding(bind);
951
952   return ret;
953 }
954   
955 /***********************************************************************
956  *             RpcBindingToStringBindingA (RPCRT4.@)
957  */
958 RPC_STATUS WINAPI RpcBindingToStringBindingA( RPC_BINDING_HANDLE Binding, LPSTR* StringBinding )
959 {
960   RPC_STATUS ret;
961   RpcBinding* bind = (RpcBinding*)Binding;
962   LPSTR ObjectUuid;
963
964   TRACE("(%p,%p)\n", Binding, StringBinding);
965
966   ret = UuidToStringA(&bind->ObjectUuid, (unsigned char**)&ObjectUuid);
967   if (ret != RPC_S_OK) return ret;
968
969   ret = RpcStringBindingComposeA(ObjectUuid, bind->Protseq, bind->NetworkAddr,
970                                  bind->Endpoint, NULL, StringBinding);
971
972   RpcStringFreeA((unsigned char**)&ObjectUuid);
973
974   return ret;
975 }
976   
977 /***********************************************************************
978  *             RpcBindingToStringBindingW (RPCRT4.@)
979  */
980 RPC_STATUS WINAPI RpcBindingToStringBindingW( RPC_BINDING_HANDLE Binding, LPWSTR* StringBinding )
981 {
982   RPC_STATUS ret;
983   LPSTR str = NULL;
984   TRACE("(%p,%p)\n", Binding, StringBinding);
985   ret = RpcBindingToStringBindingA(Binding, &str);
986   *StringBinding = RPCRT4_strdupAtoW(str);
987   RpcStringFreeA((unsigned char**)&str);
988   return ret;
989 }
990
991 /***********************************************************************
992  *             I_RpcBindingSetAsync (RPCRT4.@)
993  * NOTES
994  *  Exists in win9x and winNT, but with different number of arguments
995  *  (9x version has 3 arguments, NT has 2).
996  */
997 RPC_STATUS WINAPI I_RpcBindingSetAsync( RPC_BINDING_HANDLE Binding, RPC_BLOCKING_FN BlockingFn)
998 {
999   RpcBinding* bind = (RpcBinding*)Binding;
1000
1001   TRACE( "(%p,%p): stub\n", Binding, BlockingFn );
1002
1003   bind->BlockingFn = BlockingFn;
1004
1005   return RPC_S_OK;
1006 }