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