1 // PInvokeCE.cs 2006-12 http://www.xmlBlaster.org/
2 // Simple layer to delegate C# calls to Windows CE xmlBlaster client C library
3 // Using P/Invoke of the .NET 1.0 is not tested
4 // Using P/Invoke of the .NET 2.0 is fully supported
5 // Using P/Invoke of the .NET Compact Framework 2.0 (CF2) is fully supported
6 // Using P/Invoke of the .NET Compact Framework 1.0 does NOT support callbacks
7 //
8 // You need on CE:
9 // xmlBlasterClientC-Arm4.dll
10 // pthreads270-Arm4.dll
11 // zlib123-Arm4.dll
12 // You need on Windows:
13 // xmlBlasterClientC.dll
14 // pthreads270.dll
15 // zlib123.dll
16 //
17 // Currently only tested on normal Windows (.net 2) and Windows CE 4.2 and 5.1 (CF2) with ARM processor
18 //
19 // o All DLL C code is 'multibyte characters' of type UTF-8 written as 'char *'
20 // o All C# code is 'wchar_t' UTF-16
21 // o For 'string' we do all conversion from/to UTF-8 in C# and transfer byte[] to 'char *' in C
22 // o char * are allocated in the C-DLL and freed in the C-DLL
23 //
24 // Features: All features of the client C library (compression, tunnel callbacks), see
25 // http://www.xmlblaster.org/xmlBlaster/doc/requirements/client.c.socket.html
26 //
27 // IMPORTANT: The dll are assumed in the current directory or in the %PATH%
28 // On Linux set the LD_LIBRARY_PATH to find the .so libraries.
29 // The ARM compatible dll's contain an '-Arm4' postfix like xmlBlasterClientC-Arm4.dll
30 //
31 // @todo publishOneway crashes
32 // logging with log4net
33 // write a testsuite
34 // write a requirement
35 // create an assembly with ant or nant
36 // create the same wrapper for the xmlBlaster C++ library
37 //
38 // @author xmlBlaster@marcelruff.info
39 //
40 // @prepare Compile the C client library first (see xmlBlaster\src\c\xmlBlasterClientC.sln)
41 //
42 // @see http://www.xmlblaster.org/xmlBlaster/doc/requirements/client.csharp.html
43 // @see http://msdn.microsoft.com/mobility/understanding/articles/default.aspx?pull=/library/en-us/dnnetcomp/html/netcfintrointerp.asp?frame=true
44 // @see http://msdn.microsoft.com/mobility/understanding/articles/default.aspx?pull=/library/en-us/dnnetcomp/html/netcfadvinterop.asp
45 //
46 // @see Callback function pointers: http://msdn2.microsoft.com/en-us/library/5zwkzwf4.aspx
47 // @c http://www.xmlBlaster/org
48
49 //
50 /*
51 Usage:
52 XmlBlaster C SOCKET client
53
54 -dispatch/connection/plugin/socket/hostname [localhost]
55 Where to find xmlBlaster.
56 -dispatch/connection/plugin/socket/port [7607]
57 The port where xmlBlaster listens.
58 -dispatch/connection/plugin/socket/localHostname [NULL]
59 Force the local IP, useful on multi homed computers.
60 -dispatch/connection/plugin/socket/localPort [0]
61 Force the local port, useful to tunnel firewalls.
62 -dispatch/connection/plugin/socket/compress/type []
63 Switch on compression with 'zlib:stream'.
64 -dispatch/connection/plugin/socket/useUdpForOneway [false]
65 Use UDP for publishOneway() calls.
66 -dispatch/callback/plugin/socket/hostname [localhost]
67 The IP where to establish the callback server.
68 Can be useful on multi homed hosts.
69 -dispatch/callback/plugin/socket/port [7611]
70 The port of the callback server.
71 -plugin/socket/multiThreaded [true]
72 If true the update() call to your client code is a separate thread.
73 -plugin/socket/responseTimeout [60000 (one minute)]
74 The time in millis to wait on a response, 0 is forever.
75 -logLevel ERROR | WARN | INFO | TRACE | DUMP [WARN]
76
77 Example:
78 TestPInvoke -logLevel TRACE -dispatch/connection/plugin/socket/hostname 192.168.2.9
79 *
80 Preprocessor:
81 XMLBLASTER_MONO
82 Forces support in a Linux mono environment
83 WINCE || Smartphone || PocketPC || WindowsCE || FORCE_PINVOKECE
84 Any single of the above will force Windows CE compatibility
85 CF1 To have Windows CE compact framework .net 1.x support,
86 no callbacks are available in this case.
87 Please choose to install CF2 on your PDA and leave this define away.
88 DOTNET1 To force old .net 1.x, not tested, for Windows XP etc only
89 */
90
91 // Initial defines cleanup:
92 // In our code we only use
93 // XMLBLASTER_MONO
94 // XMLBLASTER_WINCE
95 // XMLBLASTER_WIN32
96 // CF1
97 // DOTNET1
98 // FORCE_CDELC
99 // NOTE: mono compiler is buggy and can't handle nested #if !
100 #if XMLBLASTER_MONO
101 # warning INFO: We compile on a Linux mono box
102 #endif
103
104 #if (WINCE || Smartphone || PocketPC || WindowsCE || CF1)
105 // VC2005 automatically set 'WindowsCE' for Mobile (Windows CE 5.0)
106 // and typically one of the other defines for Smart Devices 2003
107 # define XMLBLASTER_WINCE
108 # warning INFO: We compile for Windows CE compact framework .net
109 #endif
110
111 #if !(WINCE || Smartphone || PocketPC || WindowsCE || CF1) && !XMLBLASTER_MONO // Assume WIN32
112 # define XMLBLASTER_WIN32
113 # warning INFO: We compile for Windows .net target
114 #endif
115
116 #if CF1
117 # warning We compile for Windows CE compact framework .net 1.0, no xmlBlaster callback are available!
118 #endif
119
120 #if DOTNET1
121 # warning We compile for Windows .net 1.x, no xmlBlaster callback are implemented!
122 #endif
123
124 // Setting local defines
125 #if (XMLBLASTER_WIN32 || XMLBLASTER_MONO) && !DOTNET1
126 # define FORCE_CDELC // only supported in .net 2 (cdecl is default on WINCE)
127 // # warning INFO: We use UnmanagedFunctionPointer
128 // CF1 and CF2 and .net 1.x don't support UnmanagedFunctionPointer
129 // CallingConvention=CallingConvention.Cdecl supported in .net CF1 and CF2
130 // UnmanagedFunctionPointer: new in .net 2.0
131 #endif
132
133 using System;
134 using System.Text;
135 using System.Runtime.InteropServices;
136 using System.Collections;
137
138
139 namespace org.xmlBlaster.client
140 {
141
142
143 /// Calling unmanagegd code: xmlBlasterClientC.dll
144 public class PInvokeCE : I_XmlBlasterAccess
145 {
146 static XmlBlasterLogLevel localLogLevel = XmlBlasterLogLevel.INFO; // TODO: log4net
147 private bool initializeIsCalled = false;
148
149 # if XMLBLASTER_MONO
150 // Linux Debug libxmlBlasterClientCD.so, set LD_LIBRARY_PATH to find the shared library
151 const string XMLBLASTER_C_LIBRARY = "xmlBlasterClientCD";
152 # elif XMLBLASTER_WINCE // xmlBlasterClientC-$(ARCHFAM).dll
153 const string XMLBLASTER_C_LIBRARY = "xmlBlasterClientC-ARM.dll";
154 # else // XMLBLASTER_WIN32
155 const string XMLBLASTER_C_LIBRARY = "xmlBlasterClientC.dll";
156 //const string XMLBLASTER_C_LIBRARY = "..\\..\\lib\\xmlBlasterClientC.dll";
157 # endif
158
159 // Helper struct for DLL calls (struct does return empty IntPtr from DLL, why?
160 //[StructLayout(LayoutKind.Sequential/*, CharSet = CharSet.Unicode*/)]
161 public struct MsgUnitUnmanagedCEpublish // publish() only works with a type 'struct'?!
162 {
163 public MsgUnitUnmanagedCEpublish(bool dummy/*if a stuct*/)
164 {
165 key = IntPtr.Zero;
166 contentLen = 0;
167 content = IntPtr.Zero;
168 qos = IntPtr.Zero;
169 responseQos = IntPtr.Zero;
170 }
171 public MsgUnitUnmanagedCEpublish(string key, byte[] content, string qos)
172 {
173 this.key = stringToUtf8IntPtr(key);
174 this.contentLen = (content == null) ? 0 : content.Length;
175 this.content = byteArrayToIntPtr(content);
176 this.qos = stringToUtf8IntPtr(qos);
177 responseQos = IntPtr.Zero;
178 }
179 public IntPtr key;
180 public int contentLen;
181 public IntPtr content;
182 public IntPtr qos;
183 public IntPtr responseQos;
184 /* Has to be called exactly once if freeUnmanaged==true! */
185 public byte[] getContent(bool freeUnmanaged)
186 {
187 if (content == IntPtr.Zero) return new byte[0];
188 return byteArrayFromIntPtr(content, contentLen, freeUnmanaged);
189 }
190 /* Has to be called exactly once if freeUnmanaged==true! */
191 public string getKey(bool freeUnmanaged)
192 { // If called never: memory leak, if called twice: double free
193 if (key == IntPtr.Zero)
194 return "";
195 return stringFromUtf8IntPtr(key, freeUnmanaged);
196 }
197 /* Has to be called exactly once if freeUnmanaged==true! */
198 public string getQos(bool freeUnmanaged)
199 {
200 if (qos == IntPtr.Zero) return "";
201 return stringFromUtf8IntPtr(qos, freeUnmanaged);
202 }
203 /* Has to be called exactly once! */
204 public string getResponseQos()
205 {
206 if (responseQos == IntPtr.Zero) return "";
207 return stringFromUtf8IntPtr(key);
208 }
209 }
210
211 [StructLayout(LayoutKind.Sequential/*, CharSet = CharSet.Unicode*/)]
212 public class MsgUnitUnmanagedCEget // the get() only works with type 'class'! ?
213 {
214 public MsgUnitUnmanagedCEget()
215 {
216 key = IntPtr.Zero;
217 contentLen = 0;
218 content = IntPtr.Zero;
219 qos = IntPtr.Zero;
220 responseQos = IntPtr.Zero;
221 }
222 public MsgUnitUnmanagedCEget(string key, byte[] content, string qos)
223 {
224 this.key = stringToUtf8IntPtr(key);
225 this.contentLen = (content == null) ? 0 : content.Length;
226 this.content = byteArrayToIntPtr(content);
227 this.qos = stringToUtf8IntPtr(qos);
228 responseQos = IntPtr.Zero;
229 }
230 public IntPtr key;
231 public int contentLen;
232 public IntPtr content;
233 public IntPtr qos;
234 public IntPtr responseQos;
235 /* Has to be called exactly once! */
236 public byte[] getContent()
237 {
238 if (content == IntPtr.Zero) return new byte[0];
239 return byteArrayFromIntPtr(content, contentLen, true);
240 }
241 /* Has to be called exactly once! */
242 public string getKey()
243 { // If called never: memory leak, if called twice: double free
244 if (key == IntPtr.Zero)
245 return "";
246 return stringFromUtf8IntPtr(key, true);
247 }
248 /* Has to be called exactly once! */
249 public string getQos()
250 {
251 if (qos == IntPtr.Zero) return "";
252 return stringFromUtf8IntPtr(qos, true);
253 }
254 /* Has to be called exactly once! */
255 public string getResponseQos()
256 {
257 if (responseQos == IntPtr.Zero) return "";
258 return stringFromUtf8IntPtr(responseQos, true);
259 }
260 }
261
262 // Helper struct for DLL calls
263 public struct XmlBlasterUnmanagedCEException
264 {
265 public XmlBlasterUnmanagedCEException(bool isRemote)
266 {
267 remote = (isRemote) ? 1 : 0;
268 errorCode = IntPtr.Zero;
269 message = IntPtr.Zero;
270 }
271 public int remote;
272 public IntPtr errorCode;
273 public IntPtr message;
274 public bool CaughtException()
275 {
276 return errorCode != IntPtr.Zero;
277 }
278 public string GetErrorCode()
279 {
280 return stringFromUtf8IntPtr(errorCode);
281 }
282 public string GetMessage()
283 {
284 return stringFromUtf8IntPtr(message);
285 }
286 }
287
288 //public struct QosArr
289 //{
290 // public int len; /* Number of XML QoS strings */
291 // public string[] qosArr;
292 //}
293
294 //public struct MsgUnitUnmanagedCEArr
295 //{
296 // public string secretSessionId;
297 // public int len;
298 // public MsgUnit[] msgUnitArr;
299 //}
300
301
302 [StructLayout(LayoutKind.Sequential/*, CharSet = CharSet.Unicode*/)]
303 public class StringArr
304 {
305 public IntPtr str;
306 }
307
308 public void log(String str)
309 {
310 logger(XmlBlasterLogLevel.TRACE, "", str);
311 }
312
313 public void logger(XmlBlasterLogLevel level, String location, String message)
314 {
315 //logLevel.ToString("d")
316 if ((int)level <= (int)localLogLevel) { // TODO: log4net
317 if (null != onLogging)
318 {
319 try
320 {
321 onLogging((XmlBlasterLogLevel)level, location, message); // Dispatch to C# clients
322 }
323 catch (Exception e)
324 {
325 System.Diagnostics.Debug.WriteLine(e.ToString());
326 Console.WriteLine(e.ToString());
327 }
328 }
329 else {
330 string prefix = (location != null && location.Length > 0) ? location : "[PInvoke]";
331 prefix += " " + level + ": ";
332 System.Diagnostics.Debug.WriteLine(prefix + message);
333 Console.WriteLine(prefix + message);
334 }
335 }
336 }
337
338 # if FORCE_CDELC
339 [System.Runtime.InteropServices.UnmanagedFunctionPointer(System.Runtime.InteropServices.CallingConvention.Cdecl)]
340 # endif
341 public delegate void LoggerUnmanagedFp(int level, IntPtr location, IntPtr message);
342
343 /// Callback by xmlBlaster C dll, see LoggerUnmanagedFp
344 /// message pointer is NOT freed here, it is freed by the calling C DLL after this call
345 void loggerUnmanaged(int level, IntPtr location, IntPtr message)
346 {
347 string loc = stringFromUtf8IntPtr(location, false);
348 string msg = stringFromUtf8IntPtr(message, false);
349 XmlBlasterLogLevel logLevel = (XmlBlasterLogLevel)level;
350 logger(logLevel, loc, msg);
351 }
352
353 # if FORCE_CDELC
354 [System.Runtime.InteropServices.UnmanagedFunctionPointer(System.Runtime.InteropServices.CallingConvention.Cdecl)]
355 # endif
356 public delegate void ProgressUnmanagedFp(int currBytesRead, int nbytes);
357 void callbackProgressUnmanaged(int currBytesRead, int nbytes)
358 {
359 //Console.WriteLine("#####################" + currBytesRead + "/" + nbytes + " bytes read from socket");
360 logger(XmlBlasterLogLevel.INFO, "", "" + currBytesRead + "/" + nbytes + " bytes read from socket");
361 }
362
363 # if FORCE_CDELC
364 [System.Runtime.InteropServices.UnmanagedFunctionPointer(System.Runtime.InteropServices.CallingConvention.Cdecl)]
365 # endif
366 public delegate int FPtr(int value);
367
368 # if FORCE_CDELC
369 [System.Runtime.InteropServices.UnmanagedFunctionPointer(System.Runtime.InteropServices.CallingConvention.Cdecl)]
370 # endif
371 public delegate void UpdateUnmanagedFp(IntPtr cbSessionId, ref MsgUnitUnmanagedCEpublish msgUnit, int isOneway, ref XmlBlasterUnmanagedCEException exception);
372
373 /// <summary>
374 /// Helper class to set isOneway
375 /// </summary>
376 public class MsgUnitInternal : MsgUnitUpdate {
377 public MsgUnitInternal(string key, byte[] content, string qos, bool isOneway_)
378 : base(key, content, qos)
379 {
380 oneway = isOneway_;
381 }
382 }
383
384 /// Callback by xmlBlaster C dll, see UpdateUnmanagedFp and XmlBlasterUnmanagedCE.h
385 /// The cbSessionId_ and msgUnitUnmanaged is freed by the caller
386 /// The return should be a string, but this is difficult over P/Invoke, we would
387 /// need to solve it by an out parameter. But xmlBlaster ignores it currently so it is an open TODO
388 /// Info about callback function pointer: http://msdn2.microsoft.com/en-us/library/5zwkzwf4.aspx
389 /// Nice example how to pass a pointer to a managed object to DLL
390 /// and on callback cast it again to the managed object:
391 /// http://msdn2.microsoft.com/en-us/library/44ey4b32.aspx
392 /// See http://msdn2.microsoft.com/en-us/library/ss9sb93t.aspx
393 /// Samples: http://msdn2.microsoft.com/en-us/library/fzhhdwae.aspx
394 void updateUnmanaged(IntPtr cbSessionId_, ref MsgUnitUnmanagedCEpublish msgUnitUnmanaged, int isOneway_, ref XmlBlasterUnmanagedCEException exception)
395 {
396 bool isOneway = isOneway_ == 1;
397 logger(XmlBlasterLogLevel.TRACE, "", "Entering updateUnmanaged() isOneway=" + isOneway);
398 string cbSessionId = stringFromUtf8IntPtr(cbSessionId_, false);
399 //fillUnmanagedException(ref exception, "user.internal", "a test exception from C#");
400
401 MsgUnitUpdate msgUnit = new MsgUnitInternal(msgUnitUnmanaged.getKey(false),
402 msgUnitUnmanaged.getContent(false), msgUnitUnmanaged.getQos(false),
403 isOneway);
404 if (null != onUpdate)
405 {
406 try
407 {
408 string ret = onUpdate(cbSessionId, msgUnit);
409 logger(XmlBlasterLogLevel.TRACE, "", "Ignoring " + ret);
410 }
411 catch (XmlBlasterException e)
412 {
413 logger(XmlBlasterLogLevel.WARN, "", "onUpdate() exception: " + e.ToString());
414 fillUnmanagedException(ref exception, e.ErrorCode, e.Message);
415 }
416 catch (Exception e)
417 {
418 logger(XmlBlasterLogLevel.ERROR, "", "onUpdate() exception: " + e.ToString());
419 fillUnmanagedException(ref exception, "user.update.internalError", e.ToString());
420 }
421 return;
422 }
423 logger(XmlBlasterLogLevel.INFO, "", "updateUnmanaged got message " + msgUnit.GetKeyStr());
424 logger(XmlBlasterLogLevel.TRACE, "", "updateUnmanaged invoked START ==================");
425 logger(XmlBlasterLogLevel.TRACE, "", msgUnit.GetKeyStr());
426 logger(XmlBlasterLogLevel.TRACE, "", msgUnit.GetContentStr());
427 logger(XmlBlasterLogLevel.TRACE, "", msgUnit.GetQosStr());
428 logger(XmlBlasterLogLevel.TRACE, "", "updateUnmanaged invoked DONE ===================");
429 //string ret = "<qos><state id='OK'/></qos>";
430 //return ret;
431 }
432
433 /**
434 * Allocates native C memory.
435 * You need to call
436 * xmlBlasterUnmanagedCEExceptionFree(XmlBlasterUnmanagedCEException *exception)
437 * later!
438 */
439 void fillUnmanagedException(ref XmlBlasterUnmanagedCEException outE, string errorCode, string message)
440 {
441 outE.errorCode = stringToUtf8IntPtr(errorCode);
442 outE.message = stringToUtf8IntPtr(message);
443 outE.remote = 1;
444 }
445
446 /**
447 * Copy the unmanaged data to our XmlBlasterException and
448 * frees the native memory.
449 */
450 XmlBlasterException fillXmlBlasterException(ref XmlBlasterUnmanagedCEException exception)
451 {
452 XmlBlasterException managed = new XmlBlasterException(exception.remote != 0,
453 stringFromUtf8IntPtr(exception.errorCode, false),
454 stringFromUtf8IntPtr(exception.message, false));
455 xmlBlasterUnmanagedCEExceptionFree(ref exception);
456 return managed;
457 }
458
459 /**
460 * Convert a string to a UTF-8 encoded byte array.
461 * @param str UTF-16 C# string
462 * @return UTF-8 multibyte array to be passed to C dll (zero terminated)
463 */
464 public static byte[] StringToUtf8ByteArray(string str)
465 {
466 if (str == null) return new byte[0];
467 byte[] data = System.Text.Encoding.UTF8.GetBytes(str);
468 return data;
469 }
470
471 /**
472 * Convert a UTF-8 byte array to a UTF-16 string
473 * @param dBytes UTF-8 multibyte string from C (zero terminated)
474 * @return string to be used in C#
475 */
476 public static string Utf8ByteArrayToString(byte[] dBytes)
477 {
478 string str;
479 str = System.Text.Encoding.UTF8.GetString(dBytes, 0, dBytes.Length);
480 return str;
481 }
482
483 /**
484 * Allocates native memory
485 * @param str The UTF-16 unicode string to transfer
486 * @return Contains zero terminated UTF-8,
487 * the pointer memory needs to be freed with xmlBlasterUnmanagedCEFree(IntPtr).
488 * All xmlBlasterUnmanagedCEXXX() calls free the 'char *' or 'char **'
489 * passed in the dll, so we don't have to do it here in C#
490 */
491 static IntPtr stringToUtf8IntPtr(string str)
492 {
493 byte[] bytes = StringToUtf8ByteArray(str);
494 return byteArrayToIntPtr(bytes);
495 }
496
497 /**
498 * Allocates native memory
499 * @param e The byte array to transfer
500 * @return C allocated char * of length e.Length() (+ 1 as we add a zero in case of strings)
501 * the pointer memory needs to be freed with xmlBlasterUnmanagedCEFree(IntPtr).
502 * All xmlBlasterUnmanagedCEXXX() calls free the 'char *' or 'char **'
503 * passed in the dll, so we don't have to do it here in C#
504 */
505 unsafe static IntPtr byteArrayToIntPtr(byte[] e)
506 {
507 // See http://msdn2.microsoft.com/en-us/library/aa497275.aspx#Q4rlim632
508 // "How do I convert a byte[] to an IntPtr?"
509 IntPtr ptr = xmlBlasterUnmanagedCEMalloc(e.Length + 1); // is fixed(...) already
510 byte* bp = (byte*)ptr.ToPointer();
511 for (int i = 0; i < e.Length; i++)
512 {
513 bp[i] = e[i];
514 }
515 bp[e.Length] = 0;
516 return ptr;
517 }
518
519 /**
520 * Handling a DLL C function which returns a malloced char *
521 *
522 * As the following throws NotSupportedException on Windows CE
523 * byte[] tmp = stringReturner();
524 * we have a workaround and return an IntPtr.
525 * The string which was allocated in the DLL C code is
526 * extracted here and then freed by a call to
527 * xmlBlasterFree(IntPtr)
528 * @param ptr A C malloced 'char *' containing UTF-8 text
529 * @return A unicode 'wchar_t *' UTF-16 string
530 */
531 static string stringFromUtf8IntPtr(IntPtr ptr)
532 {
533 return stringFromUtf8IntPtr(ptr, true);
534 }
535
536 static string stringFromUtf8IntPtr(IntPtr ptr, bool freeUnmanaged)
537 {
538 if (ptr == IntPtr.Zero) return "";
539 byte[] bytes = byteArrayFromIntPtr(ptr, -1, freeUnmanaged);
540 return Utf8ByteArrayToString(bytes);
541 }
542
543 /**
544 * @param contentLen
545 * @param freeUnmanaged If true we call the native C DLL and free() the memory pointed to by ptr
546 */
547
548 /// <summary>
549 /// Convenience method for zero terminated string in IntPtr which shall be read and free()d
550 /// </summary>
551 /// <param name="contentLen">If -1 we parse until we reach the first 0, else we parse the given length</param>
552 /// <param name="freeUnmanaged">If true we call the native C DLL and free() the memory pointed to by ptr</param>
553 /// <returns></returns>
554 unsafe static byte[] byteArrayFromIntPtr(IntPtr ptr, int contentLen, bool freeUnmanaged)
555 {
556 if (ptr == IntPtr.Zero) return new byte[0];
557 //Can't cast type 'System.IntPtr' to 'byte[]'
558 // byte[] tmp = (byte[])stringReturner();
559 //so we need to copy it manually:
560 void* vPtr = ptr.ToPointer(); // is fixed(...) already
561 byte* tmpP = (byte*)vPtr;
562 int len = contentLen;
563 if (contentLen < 0)
564 for (len = 0; tmpP[len] != 0; len++) ;
565 byte[] tmp = new byte[len];
566 for (int i = 0; i < tmp.Length; i++)
567 tmp[i] = tmpP[i];
568 // Now free() the malloc() IntPtr in the C DLL ...
569 if (freeUnmanaged) xmlBlasterUnmanagedCEFree(ptr);
570 return tmp;
571 }
572
573 [DllImport(XMLBLASTER_C_LIBRARY)]
574 private extern static IntPtr xmlBlasterUnmanagedCEMalloc(int size);
575
576 [DllImport(XMLBLASTER_C_LIBRARY)]
577 private extern static void xmlBlasterUnmanagedCEFree(IntPtr p);
578
579 [DllImport(XMLBLASTER_C_LIBRARY)]
580 private extern static IntPtr getXmlBlasterEmei();
581
582 [DllImport(XMLBLASTER_C_LIBRARY)]
583 private extern static void xmlBlasterUnmanagedCERegisterLogger(IntPtr xa, IntPtr loggerUnmanaged);
584
585 [DllImport(XMLBLASTER_C_LIBRARY)]
586 private extern static void xmlBlasterUnmanagedCERegisterProgressListener(IntPtr xa, IntPtr progressUnmanaged);
587
588 [DllImport(XMLBLASTER_C_LIBRARY)]
589 private extern static void xmlBlasterUnmanagedCEFreePP(out IntPtr p);
590
591 [DllImport(XMLBLASTER_C_LIBRARY)]
592 private extern static void xmlBlasterUnmanagedCEExceptionFree(ref XmlBlasterUnmanagedCEException exception);
593
594 [DllImport(XMLBLASTER_C_LIBRARY)]
595 private extern static IntPtr getXmlBlasterAccessUnparsedUnmanagedCE(int argc, IntPtr[] argv);
596
597 [DllImport(XMLBLASTER_C_LIBRARY)]
598 private extern static void freeXmlBlasterAccessUnparsedUnmanagedCE(IntPtr xa);
599
600 [DllImport(XMLBLASTER_C_LIBRARY)]
601 private extern static IntPtr xmlBlasterUnmanagedCEConnect(IntPtr xa, IntPtr qos, IntPtr updateUnmanaged, ref XmlBlasterUnmanagedCEException exception);
602
603 [DllImport(XMLBLASTER_C_LIBRARY)]
604 private extern static bool xmlBlasterUnmanagedCEInitialize(IntPtr xa, IntPtr updateUnmanaged, ref XmlBlasterUnmanagedCEException exception);
605
606 [DllImport(XMLBLASTER_C_LIBRARY)]
607 private extern static bool xmlBlasterUnmanagedCEDisconnect(IntPtr xa, IntPtr qos, ref XmlBlasterUnmanagedCEException exception);
608
609 [DllImport(XMLBLASTER_C_LIBRARY)]
610 private extern static IntPtr xmlBlasterUnmanagedCEPublish(IntPtr xa, out MsgUnitUnmanagedCEpublish msgUnit, ref XmlBlasterUnmanagedCEException exception);
611
612 //[DllImport(XMLBLASTER_C_LIBRARY )]
613 //private extern static QosArr xmlBlasterUnmanagedCEPublishArr(IntPtr xa, MsgUnitUnmanagedCEArr msgUnitArr, ref XmlBlasterUnmanagedCEException exception);
614
615 [DllImport(XMLBLASTER_C_LIBRARY)]
616 private extern static void xmlBlasterUnmanagedCEPublishOneway(IntPtr xa, IntPtr msgUnitArr, int length, ref XmlBlasterUnmanagedCEException exception);
617
618 [DllImport(XMLBLASTER_C_LIBRARY)]
619 private extern static IntPtr xmlBlasterUnmanagedCESubscribe(IntPtr xa, IntPtr key, IntPtr qos, ref XmlBlasterUnmanagedCEException exception);
620
621 [DllImport(XMLBLASTER_C_LIBRARY)]
622 private extern static void xmlBlasterUnmanagedCEUnSubscribe(IntPtr xa, IntPtr key, IntPtr qos,
623 ref XmlBlasterUnmanagedCEException exception, out int size, out IntPtr ptr);
624
625 [DllImport(XMLBLASTER_C_LIBRARY)]
626 private extern static void xmlBlasterUnmanagedCEErase(IntPtr xa, IntPtr key, IntPtr qos,
627 ref XmlBlasterUnmanagedCEException exception, out int size, out IntPtr ptr);
628
629 [DllImport(XMLBLASTER_C_LIBRARY)]
630 private extern static void xmlBlasterUnmanagedCEGet(IntPtr xa, IntPtr key, IntPtr qos,
631 ref XmlBlasterUnmanagedCEException exception, out int size, out IntPtr ptr);
632
633 [DllImport(XMLBLASTER_C_LIBRARY)]
634 private extern static IntPtr xmlBlasterUnmanagedCEPing(IntPtr xa, IntPtr qos, ref XmlBlasterUnmanagedCEException exception);
635
636 [DllImport(XMLBLASTER_C_LIBRARY)]
637 private extern static bool xmlBlasterUnmanagedCEIsConnected(IntPtr xa);
638
639 [DllImport(XMLBLASTER_C_LIBRARY)]
640 private extern static IntPtr xmlBlasterUnmanagedCEUsage();
641
642 [DllImport(XMLBLASTER_C_LIBRARY)]
643 private extern static IntPtr xmlBlasterUnmanagedCEVersion();
644
645 private IntPtr xa;
646 private UpdateUnmanagedFp updateUnmanagedFp;
647 private LoggerUnmanagedFp loggerUnmanagedFp;
648 private ProgressUnmanagedFp progressUnmanagedFp;
649 private IntPtr updateFpForDelegate;
650 private IntPtr loggerFpForDelegate;
651 private IntPtr progressFpForDelegate;
652 /** Is not null if the client wishes to be notified about connection state changes in fail safe operation */
653 private I_ConnectionStateListener connectionListener;
654
655 public PInvokeCE() {
656 }
657
658 /// <summary>
659 /// Convenience method, calls initialize()
660 /// </summary>
661 /// <param name="argv">argv [0] contains the first argument, etc.
662 /// "-dispatch/connection/plugin/socket/hostname" "192.168.1.2"</param>
663 public PInvokeCE(string[] argv)
664 {
665 Initialize(toHashtable(argv));
666 }
667
668 public static Hashtable toHashtable(string[] argv)
669 {
670 Hashtable hash = new Hashtable();
671 //hash.Add("__exe__", "PInvokeCE");
672 for (int i = 0; i < argv.Length; ++i)
673 {
674 string key = (argv[i].StartsWith("-"))?argv[i].Substring(1):argv[i];
675 string value = "";
676 if (i < (argv.Length -1)) {
677 i++;
678 value = argv[i];
679 }
680 hash.Add(key, value);
681 }
682 return hash;
683 }
684
685 /// <summary>
686 /// Convert command line arguments: C client lib expects the executable name as first entry
687 /// </summary>
688 /// <param name="hash"></param>
689 /// <returns></returns>
690 private IntPtr[] create_C_args(Hashtable hash) {
691 int c_argc = 2 * hash.Count + 1;
692
693 IntPtr[] c_argv = new IntPtr[c_argc];
694 c_argv[0] = stringToUtf8IntPtr("PInvokeCE"); // TODO: my executable name
695
696 ArrayList aKeys = new ArrayList(hash.Keys);
697 int i = 1;
698 foreach (string key_ in aKeys) {
699 string value = (string)hash[key_];
700 if (value == null) value = "";
701 string key = (key_.StartsWith(