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 # if DEBUG
156 const string XMLBLASTER_C_LIBRARY = "xmlBlasterClientCD.dll";
157 # else
158 const string XMLBLASTER_C_LIBRARY = "xmlBlasterClientC.dll";
159 //const string XMLBLASTER_C_LIBRARY = "..\\..\\lib\\xmlBlasterClientC.dll";
160 # endif
161 # endif
162
163 // Helper struct for DLL calls (struct does return empty IntPtr from DLL, why?
164 //[StructLayout(LayoutKind.Sequential/*, CharSet = CharSet.Unicode*/)]
165 public struct MsgUnitUnmanagedCEpublish // publish() only works with a type 'struct'?!
166 {
167 public MsgUnitUnmanagedCEpublish(bool dummy/*if a stuct*/)
168 {
169 key = IntPtr.Zero;
170 contentLen = 0;
171 content = IntPtr.Zero;
172 qos = IntPtr.Zero;
173 responseQos = IntPtr.Zero;
174 }
175 public MsgUnitUnmanagedCEpublish(string key, byte[] content, string qos)
176 {
177 this.key = stringToUtf8IntPtr(key);
178 this.contentLen = (content == null) ? 0 : content.Length;
179 this.content = byteArrayToIntPtr(content);
180 this.qos = stringToUtf8IntPtr(qos);
181 responseQos = IntPtr.Zero;
182 }
183 public IntPtr key;
184 public int contentLen;
185 public IntPtr content;
186 public IntPtr qos;
187 public IntPtr responseQos;
188 /* Has to be called exactly once if freeUnmanaged==true! */
189 public byte[] getContent(bool freeUnmanaged)
190 {
191 if (content == IntPtr.Zero) return new byte[0];
192 return byteArrayFromIntPtr(content, contentLen, freeUnmanaged);
193 }
194 /* Has to be called exactly once if freeUnmanaged==true! */
195 public string getKey(bool freeUnmanaged)
196 { // If called never: memory leak, if called twice: double free
197 if (key == IntPtr.Zero)
198 return "";
199 return stringFromUtf8IntPtr(key, freeUnmanaged);
200 }
201 /* Has to be called exactly once if freeUnmanaged==true! */
202 public string getQos(bool freeUnmanaged)
203 {
204 if (qos == IntPtr.Zero) return "";
205 return stringFromUtf8IntPtr(qos, freeUnmanaged);
206 }
207 /* Has to be called exactly once! */
208 public string getResponseQos()
209 {
210 if (responseQos == IntPtr.Zero) return "";
211 return stringFromUtf8IntPtr(key);
212 }
213 }
214
215 [StructLayout(LayoutKind.Sequential/*, CharSet = CharSet.Unicode*/)]
216 public class MsgUnitUnmanagedCEget // the get() only works with type 'class'! ?
217 {
218 public MsgUnitUnmanagedCEget()
219 {
220 key = IntPtr.Zero;
221 contentLen = 0;
222 content = IntPtr.Zero;
223 qos = IntPtr.Zero;
224 responseQos = IntPtr.Zero;
225 }
226 public MsgUnitUnmanagedCEget(string key, byte[] content, string qos)
227 {
228 this.key = stringToUtf8IntPtr(key);
229 this.contentLen = (content == null) ? 0 : content.Length;
230 this.content = byteArrayToIntPtr(content);
231 this.qos = stringToUtf8IntPtr(qos);
232 responseQos = IntPtr.Zero;
233 }
234 public IntPtr key;
235 public int contentLen;
236 public IntPtr content;
237 public IntPtr qos;
238 public IntPtr responseQos;
239 /* Has to be called exactly once! */
240 public byte[] getContent()
241 {
242 if (content == IntPtr.Zero) return new byte[0];
243 return byteArrayFromIntPtr(content, contentLen, true);
244 }
245 /* Has to be called exactly once! */
246 public string getKey()
247 { // If called never: memory leak, if called twice: double free
248 if (key == IntPtr.Zero)
249 return "";
250 return stringFromUtf8IntPtr(key, true);
251 }
252 /* Has to be called exactly once! */
253 public string getQos()
254 {
255 if (qos == IntPtr.Zero) return "";
256 return stringFromUtf8IntPtr(qos, true);
257 }
258 /* Has to be called exactly once! */
259 public string getResponseQos()
260 {
261 if (responseQos == IntPtr.Zero) return "";
262 return stringFromUtf8IntPtr(responseQos, true);
263 }
264 }
265
266 // Helper struct for DLL calls
267 public struct XmlBlasterUnmanagedCEException
268 {
269 public XmlBlasterUnmanagedCEException(bool isRemote)
270 {
271 remote = (isRemote) ? 1 : 0;
272 errorCode = IntPtr.Zero;
273 message = IntPtr.Zero;
274 }
275 public int remote;
276 public IntPtr errorCode;
277 public IntPtr message;
278 public bool CaughtException()
279 {
280 return errorCode != IntPtr.Zero;
281 }
282 public string GetErrorCode()
283 {
284 return stringFromUtf8IntPtr(errorCode);
285 }
286 public string GetMessage()
287 {
288 return stringFromUtf8IntPtr(message);
289 }
290 }
291
292 //public struct QosArr
293 //{
294 // public int len; /* Number of XML QoS strings */
295 // public string[] qosArr;
296 //}
297
298 //public struct MsgUnitUnmanagedCEArr
299 //{
300 // public string secretSessionId;
301 // public int len;
302 // public MsgUnit[] msgUnitArr;
303 //}
304
305
306 [StructLayout(LayoutKind.Sequential/*, CharSet = CharSet.Unicode*/)]
307 public class StringArr
308 {
309 public IntPtr str;
310 }
311
312 public void log(String str)
313 {
314 logger(XmlBlasterLogLevel.TRACE, "", str);
315 }
316
317 public void logger(XmlBlasterLogLevel level, String location, String message)
318 {
319 //logLevel.ToString("d")
320 if ((int)level <= (int)localLogLevel) { // TODO: log4net
321 if (null != onLogging)
322 {
323 try
324 {
325 onLogging((XmlBlasterLogLevel)level, location, message); // Dispatch to C# clients
326 }
327 catch (Exception e)
328 {
329 System.Diagnostics.Debug.WriteLine(e.ToString());
330 Console.WriteLine(e.ToString());
331 }
332 }
333 else {
334 string prefix = (location != null && location.Length > 0) ? location : "[PInvoke]";
335 prefix += " " + level + ": ";
336 System.Diagnostics.Debug.WriteLine(prefix + message);
337 Console.WriteLine(prefix + message);
338 }
339 }
340 }
341
342 # if FORCE_CDELC
343 [System.Runtime.InteropServices.UnmanagedFunctionPointer(System.Runtime.InteropServices.CallingConvention.Cdecl)]
344 # endif
345 public delegate void LoggerUnmanagedFp(int level, IntPtr location, IntPtr message);
346
347 /// Callback by xmlBlaster C dll, see LoggerUnmanagedFp
348 /// message pointer is NOT freed here, it is freed by the calling C DLL after this call
349 void loggerUnmanaged(int level, IntPtr location, IntPtr message)
350 {
351 string loc = stringFromUtf8IntPtr(location, false);
352 string msg = stringFromUtf8IntPtr(message, false);
353 XmlBlasterLogLevel logLevel = (XmlBlasterLogLevel)level;
354 logger(logLevel, loc, msg);
355 }
356
357 # if FORCE_CDELC
358 [System.Runtime.InteropServices.UnmanagedFunctionPointer(System.Runtime.InteropServices.CallingConvention.Cdecl)]
359 # endif
360 public delegate void ProgressUnmanagedFp(int currBytesRead, int nbytes);
361 void callbackProgressUnmanaged(int currBytesRead, int nbytes)
362 {
363 //Console.WriteLine("#####################" + currBytesRead + "/" + nbytes + " bytes read from socket");
364 logger(XmlBlasterLogLevel.INFO, "", "" + currBytesRead + "/" + nbytes + " bytes read from socket");
365 }
366
367 # if FORCE_CDELC
368 [System.Runtime.InteropServices.UnmanagedFunctionPointer(System.Runtime.InteropServices.CallingConvention.Cdecl)]
369 # endif
370 public delegate int FPtr(int value);
371
372 # if FORCE_CDELC
373 [System.Runtime.InteropServices.UnmanagedFunctionPointer(System.Runtime.InteropServices.CallingConvention.Cdecl)]
374 # endif
375 public delegate void UpdateUnmanagedFp(IntPtr cbSessionId, ref MsgUnitUnmanagedCEpublish msgUnit, int isOneway, ref XmlBlasterUnmanagedCEException exception);
376
377 /// <summary>
378 /// Helper class to set isOneway
379 /// </summary>
380 public class MsgUnitInternal : MsgUnitUpdate {
381 public MsgUnitInternal(string key, byte[] content, string qos, bool isOneway_)
382 : base(key, content, qos)
383 {
384 oneway = isOneway_;
385 }
386 }
387
388 /// Callback by xmlBlaster C dll, see UpdateUnmanagedFp and XmlBlasterUnmanagedCE.h
389 /// The cbSessionId_ and msgUnitUnmanaged is freed by the caller
390 /// The return should be a string, but this is difficult over P/Invoke, we would
391 /// need to solve it by an out parameter. But xmlBlaster ignores it currently so it is an open TODO
392 /// Info about callback function pointer: http://msdn2.microsoft.com/en-us/library/5zwkzwf4.aspx
393 /// Nice example how to pass a pointer to a managed object to DLL
394 /// and on callback cast it again to the managed object:
395 /// http://msdn2.microsoft.com/en-us/library/44ey4b32.aspx
396 /// See http://msdn2.microsoft.com/en-us/library/ss9sb93t.aspx
397 /// Samples: http://msdn2.microsoft.com/en-us/library/fzhhdwae.aspx
398 void updateUnmanaged(IntPtr cbSessionId_, ref MsgUnitUnmanagedCEpublish msgUnitUnmanaged, int isOneway_, ref XmlBlasterUnmanagedCEException exception)
399 {
400 bool isOneway = isOneway_ == 1;
401 logger(XmlBlasterLogLevel.TRACE, "", "Entering updateUnmanaged() isOneway=" + isOneway);
402 string cbSessionId = stringFromUtf8IntPtr(cbSessionId_, false);
403 //fillUnmanagedException(ref exception, "user.internal", "a test exception from C#");
404
405 MsgUnitUpdate msgUnit = new MsgUnitInternal(msgUnitUnmanaged.getKey(false),
406 msgUnitUnmanaged.getContent(false), msgUnitUnmanaged.getQos(false),
407 isOneway);
408 if (null != onUpdate)
409 {
410 try
411 {
412 string ret = onUpdate(cbSessionId, msgUnit);
413 logger(XmlBlasterLogLevel.TRACE, "", "Ignoring " + ret);
414 }
415 catch (XmlBlasterException e)
416 {
417 logger(XmlBlasterLogLevel.WARN, "", "onUpdate() exception: " + e.ToString());
418 fillUnmanagedException(ref exception, e.ErrorCode, e.Message);
419 }
420 catch (Exception e)
421 {
422 logger(XmlBlasterLogLevel.ERROR, "", "onUpdate() exception: " + e.ToString());
423 fillUnmanagedException(ref exception, "user.update.internalError", e.ToString());
424 }
425 return;
426 }
427 logger(XmlBlasterLogLevel.INFO, "", "updateUnmanaged got message " + msgUnit.GetKeyStr());
428 logger(XmlBlasterLogLevel.TRACE, "", "updateUnmanaged invoked START ==================");
429 logger(XmlBlasterLogLevel.TRACE, "", msgUnit.GetKeyStr());
430 logger(XmlBlasterLogLevel.TRACE, "", msgUnit.GetContentStr());
431 logger(XmlBlasterLogLevel.TRACE, "", msgUnit.GetQosStr());
432 logger(XmlBlasterLogLevel.TRACE, "", "updateUnmanaged invoked DONE ===================");
433 //string ret = "<qos><state id='OK'/></qos>";
434 //return ret;
435 }
436
437 /**
438 * Allocates native C memory.
439 * You need to call
440 * xmlBlasterUnmanagedCEExceptionFree(XmlBlasterUnmanagedCEException *exception)
441 * later!
442 */
443 void fillUnmanagedException(ref XmlBlasterUnmanagedCEException outE, string errorCode, string message)
444 {
445 outE.errorCode = stringToUtf8IntPtr(errorCode);
446 outE.message = stringToUtf8IntPtr(message);
447 outE.remote = 1;
448 }
449
450 /**
451 * Copy the unmanaged data to our XmlBlasterException and
452 * frees the native memory.
453 */
454 XmlBlasterException fillXmlBlasterException(ref XmlBlasterUnmanagedCEException exception)
455 {
456 XmlBlasterException managed = new XmlBlasterException(exception.remote != 0,
457 stringFromUtf8IntPtr(exception.errorCode, false),
458 stringFromUtf8IntPtr(exception.message, false));
459 xmlBlasterUnmanagedCEExceptionFree(ref exception);
460 return managed;
461 }
462
463 /**
464 * Convert a string to a UTF-8 encoded byte array.
465 * @param str UTF-16 C# string
466 * @return UTF-8 multibyte array to be passed to C dll (zero terminated)
467 */
468 public static byte[] StringToUtf8ByteArray(string str)
469 {
470 if (str == null) return new byte[0];
471 byte[] data = System.Text.Encoding.UTF8.GetBytes(str);
472 return data;
473 }
474
475 /**
476 * Convert a UTF-8 byte array to a UTF-16 string
477 * @param dBytes UTF-8 multibyte string from C (zero terminated)
478 * @return string to be used in C#
479 */
480 public static string Utf8ByteArrayToString(byte[] dBytes)
481 {
482 string str;
483 str = System.Text.Encoding.UTF8.GetString(dBytes, 0, dBytes.Length);
484 return str;
485 }
486
487 /**
488 * Allocates native memory
489 * @param str The UTF-16 unicode string to transfer
490 * @return Contains zero terminated UTF-8,
491 * the pointer memory needs to be freed with xmlBlasterUnmanagedCEFree(IntPtr).
492 * All xmlBlasterUnmanagedCEXXX() calls free the 'char *' or 'char **'
493 * passed in the dll, so we don't have to do it here in C#
494 */
495 static IntPtr stringToUtf8IntPtr(string str)
496 {
497 byte[] bytes = StringToUtf8ByteArray(str);
498 return byteArrayToIntPtr(bytes);
499 }
500
501 /**
502 * Allocates native memory
503 * @param e The byte array to transfer
504 * @return C allocated char * of length e.Length() (+ 1 as we add a zero in case of strings)
505 * the pointer memory needs to be freed with xmlBlasterUnmanagedCEFree(IntPtr).
506 * All xmlBlasterUnmanagedCEXXX() calls free the 'char *' or 'char **'
507 * passed in the dll, so we don't have to do it here in C#
508 */
509 unsafe static IntPtr byteArrayToIntPtr(byte[] e)
510 {
511 // See http://msdn2.microsoft.com/en-us/library/aa497275.aspx#Q4rlim632
512 // "How do I convert a byte[] to an IntPtr?"
513 IntPtr ptr = xmlBlasterUnmanagedCEMalloc(e.Length + 1); // is fixed(...) already
514 byte* bp = (byte*)ptr.ToPointer();
515 for (int i = 0; i < e.Length; i++)
516 {
517 bp[i] = e[i];
518 }
519 bp[e.Length] = 0;
520 return ptr;
521 }
522
523 /**
524 * Handling a DLL C function which returns a malloced char *
525 *
526 * As the following throws NotSupportedException on Windows CE
527 * byte[] tmp = stringReturner();
528 * we have a workaround and return an IntPtr.
529 * The string which was allocated in the DLL C code is
530 * extracted here and then freed by a call to
531 * xmlBlasterFree(IntPtr)
532 * @param ptr A C malloced 'char *' containing UTF-8 text
533 * @return A unicode 'wchar_t *' UTF-16 string
534 */
535 static string stringFromUtf8IntPtr(IntPtr ptr)
536 {
537 return stringFromUtf8IntPtr(ptr, true);
538 }
539
540 static string stringFromUtf8IntPtr(IntPtr ptr, bool freeUnmanaged)
541 {
542 if (ptr == IntPtr.Zero) return "";
543 byte[] bytes = byteArrayFromIntPtr(ptr, -1, freeUnmanaged);
544 return Utf8ByteArrayToString(bytes);
545 }
546
547 /**
548 * @param contentLen
549 * @param freeUnmanaged If true we call the native C DLL and free() the memory pointed to by ptr
550 */
551
552 /// <summary>
553 /// Convenience method for zero terminated string in IntPtr which shall be read and free()d
554 /// </summary>
555 /// <param name="contentLen">If -1 we parse until we reach the first 0, else we parse the given length</param>
556 /// <param name="freeUnmanaged">If true we call the native C DLL and free() the memory pointed to by ptr</param>
557 /// <returns></returns>
558 unsafe static byte[] byteArrayFromIntPtr(IntPtr ptr, int contentLen, bool freeUnmanaged)
559 {
560 if (ptr == IntPtr.Zero) return new byte[0];
561 //Can't cast type 'System.IntPtr' to 'byte[]'
562 // byte[] tmp = (byte[])stringReturner();
563 //so we need to copy it manually:
564 void* vPtr = ptr.ToPointer(); // is fixed(...) already
565 byte* tmpP = (byte*)vPtr;
566 int len = contentLen;
567 if (contentLen < 0)
568 for (len = 0; tmpP[len] != 0; len++) ;
569 byte[] tmp = new byte[len];
570 for (int i = 0; i < tmp.Length; i++)
571 tmp[i] = tmpP[i];
572 // Now free() the malloc() IntPtr in the C DLL ...
573 if (freeUnmanaged) xmlBlasterUnmanagedCEFree(ptr);
574 return tmp;
575 }
576
577 [DllImport(XMLBLASTER_C_LIBRARY)]
578 private extern static IntPtr xmlBlasterUnmanagedCEMalloc(int size);
579
580 [DllImport(XMLBLASTER_C_LIBRARY)]
581 private extern static void xmlBlasterUnmanagedCEFree(IntPtr p);
582
583 [DllImport(XMLBLASTER_C_LIBRARY)]
584 private extern static IntPtr getXmlBlasterEmei();
585
586 [DllImport(XMLBLASTER_C_LIBRARY)]
587 private extern static void xmlBlasterUnmanagedCERegisterLogger(IntPtr xa, IntPtr loggerUnmanaged);
588
589 [DllImport(XMLBLASTER_C_LIBRARY)]
590 private extern static void xmlBlasterUnmanagedCERegisterProgressListener(IntPtr xa, IntPtr progressUnmanaged);
591
592 [DllImport(XMLBLASTER_C_LIBRARY)]
593 private extern static void xmlBlasterUnmanagedCEFreePP(out IntPtr p);
594
595 [DllImport(XMLBLASTER_C_LIBRARY)]
596 private extern static void xmlBlasterUnmanagedCEExceptionFree(ref XmlBlasterUnmanagedCEException exception);
597
598 [DllImport(XMLBLASTER_C_LIBRARY)]
599 private extern static IntPtr getXmlBlasterAccessUnparsedUnmanagedCE(int argc, IntPtr[] argv);
600
601 [DllImport(XMLBLASTER_C_LIBRARY)]
602 private extern static void freeXmlBlasterAccessUnparsedUnmanagedCE(IntPtr xa);
603
604 [DllImport(XMLBLASTER_C_LIBRARY)]
605 private extern static IntPtr xmlBlasterUnmanagedCEConnect(IntPtr xa, IntPtr qos, IntPtr updateUnmanaged, ref XmlBlasterUnmanagedCEException exception);
606
607 [DllImport(XMLBLASTER_C_LIBRARY)]
608 private extern static bool xmlBlasterUnmanagedCEInitialize(IntPtr xa, IntPtr updateUnmanaged, ref XmlBlasterUnmanagedCEException exception);
609
610 [DllImport(XMLBLASTER_C_LIBRARY)]
611 private extern static bool xmlBlasterUnmanagedCEDisconnect(IntPtr xa, IntPtr qos, ref XmlBlasterUnmanagedCEException exception);
612
613 [DllImport(XMLBLASTER_C_LIBRARY)]
614 private extern static IntPtr xmlBlasterUnmanagedCEPublish(IntPtr xa, out MsgUnitUnmanagedCEpublish msgUnit, ref XmlBlasterUnmanagedCEException exception);
615
616 //[DllImport(XMLBLASTER_C_LIBRARY )]
617 //private extern static QosArr xmlBlasterUnmanagedCEPublishArr(IntPtr xa, MsgUnitUnmanagedCEArr msgUnitArr, ref XmlBlasterUnmanagedCEException exception);
618
619 [DllImport(XMLBLASTER_C_LIBRARY)]
620 private extern static void xmlBlasterUnmanagedCEPublishOneway(IntPtr xa, IntPtr msgUnitArr, int length, ref XmlBlasterUnmanagedCEException exception);
621
622 [DllImport(XMLBLASTER_C_LIBRARY)]
623 private extern static IntPtr xmlBlasterUnmanagedCESubscribe(IntPtr xa, IntPtr key, IntPtr qos, ref XmlBlasterUnmanagedCEException exception);
624
625 [DllImport(XMLBLASTER_C_LIBRARY)]
626 private extern static void xmlBlasterUnmanagedCEUnSubscribe(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 xmlBlasterUnmanagedCEErase(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 void xmlBlasterUnmanagedCEGet(IntPtr xa, IntPtr key, IntPtr qos,
635 ref XmlBlasterUnmanagedCEException exception, out int size, out IntPtr ptr);
636
637 [DllImport(XMLBLASTER_C_LIBRARY)]
638 private extern static IntPtr xmlBlasterUnmanagedCEPing(IntPtr xa, IntPtr qos, ref XmlBlasterUnmanagedCEException exception);
639
640 [DllImport(XMLBLASTER_C_LIBRARY)]
641 private extern static bool xmlBlasterUnmanagedCEIsConnected(IntPtr xa);
642
643 [DllImport(XMLBLASTER_C_LIBRARY)]
644 private extern static IntPtr xmlBlasterUnmanagedCEUsage();
645
646 [DllImport(XMLBLASTER_C_LIBRARY)]
647 private extern static IntPtr xmlBlasterUnmanagedCEVersion();
648
649 private IntPtr xa;
650 private UpdateUnmanagedFp updateUnmanagedFp;
651 private LoggerUnmanagedFp loggerUnmanagedFp;
652 private ProgressUnmanagedFp progressUnmanagedFp;
653 private IntPtr updateFpForDelegate;
654 private IntPtr loggerFpForDelegate;
655 private IntPtr progressFpForDelegate;
656 /** Is not null if the client wishes to be notified about connection state changes in fail safe operation */
657 private I_ConnectionStateListener connectionListener;
658
659 public PInvokeCE() {
660 }
661
662 /// <summary>
663 /// Convenience method, calls initialize()
664 /// </summary>
665 /// <param name="argv">argv [0] contains the first argument, etc.
666 /// "-dispatch/connection/plugin/socket/hostname" "192.168.1.2"</param>
667 public PInvokeCE(string[] argv)
668 {
669 Initialize(toHashtable(argv));
670 }
671
672 public static Hashtable toHashtable(string[] argv)
673 {
674 Hashtable hash = new Hashtable();
675 //hash.Add("__exe__", "PInvokeCE");
676 for (int i = 0; i < argv.Length; ++i)
677 {
678 string key = (argv[i].StartsWith("-"))?argv[i].Substring(1):argv[i];
679 string value = "";
680 if (i < (argv.Length -1)) {
681 i++;
682 value = argv[i];
683 }
684 hash.Add(key, value);
685 }
686 return hash;
687 }
688
689 /// <summary>
690 /// Convert command line arguments: C client lib expects the executable name as first entry
691 /// </summary>
692 /// <param name="hash"></param>
693 /// <returns></returns>
694 private IntPtr[] create_C_args(Hashtable hash) {
695 int c_argc = 2 * hash.Count + 1;
696
697 IntPtr[] c_argv = new IntPtr[c_argc];
698 c_argv[0] = stringToUtf8IntPtr("PInvokeCE"); // TODO: my executable name
699
700 ArrayList aKeys = new ArrayList(hash.Keys);
701 int i = 1;
702 foreach (string key_ in aKeys) {
703 string value = (string)hash[key_];
704 if (value == null) value = "";
705 string key = (key_.StartsWith("-")) ? key_ : ("-" + key_);
706 c_argv[i] = stringToUtf8IntPtr(key);
707 i++;
708 c_argv[i] = stringToUtf8IntPtr(value);
709 i++;
710 }
711 return c_argv;
712 }
713
714 public void setLogLevel(string level) {
715 # if XMLBLASTER_WINCE // Enum.GetValues is not supported
716 if ("INFO".Equals(level.ToUpper()))
717 localLogLevel = XmlBlasterLogLevel.INFO;
718 else if ("WARN".Equals(level.ToUpper()))
719 localLogLevel = XmlBlasterLogLevel.WARN;
720 else if ("ERROR".Equals(level.ToUpper()))
721 localLogLevel = XmlBlasterLogLevel.ERROR;
722 else if ("TRACE".Equals(level.ToUpper()))
723 localLogLevel = XmlBlasterLogLevel.TRACE;
724 else if ("DUMP".Equals(level.ToUpper()))
725 localLogLevel = XmlBlasterLogLevel.DUMP;
726 # else
727 Array logArray = Enum.GetValues(typeof(XmlBlasterLogLevel));
728 foreach (XmlBlasterLogLevel logLevel in logArray)
729 if (logLevel.ToString().Equals(level)) {
730 localLogLevel = logLevel;
731 break;
732 }
733 #endif
734 }
735
736 public void Initialize(string[] argv) {
737 Initialize(toHashtable(argv));
738 }
739
740 public void Initialize(Hashtable properties) {
741 if (properties == null) properties = new Hashtable();
742
743 updateUnmanagedFp = new UpdateUnmanagedFp(this.updateUnmanaged);
744 updateFpForDelegate = Marshal.GetFunctionPointerForDelegate(updateUnmanagedFp);
745
746 if (properties.Contains("-help") || properties.Contains("help")
747 || properties.Contains("/?"))
748 {
749 string usage = "Usage:\nxmlBlaster C client v" + GetVersion()
750 + " on " + System.Environment.OSVersion.ToString() +
751 #if XMLBLASTER_WINCE
752 " compact framework .net " + System.Environment.Version.ToString();
753 #else
754 " .net " + System.Environment.Version.ToString();
755 #endif
756 usage += "\n" + GetUsage();
757 logger(XmlBlasterLogLevel.TRACE, "", usage);
758 throw new XmlBlasterException("user.usage", usage);//"Good bye");
759 }
760
761 if (properties.Contains("logLevel")) {
762 setLogLevel((string)properties["logLevel"]);
763 }
764
765 IntPtr[] c_argv = create_C_args(properties);
766 // Frees not c_argv (as it crashed)
767 xa = getXmlBlasterAccessUnparsedUnmanagedCE(c_argv.Length, c_argv);
768 for (int i = 0; i < c_argv.Length; ++i)
769 xmlBlasterUnmanagedCEFree(c_argv[i]);
770
771 loggerUnmanagedFp = new LoggerUnmanagedFp(this.loggerUnmanaged);
772 loggerFpForDelegate = Marshal.GetFunctionPointerForDelegate(loggerUnmanagedFp);
773 xmlBlasterUnmanagedCERegisterLogger(xa, loggerFpForDelegate);
774
775 this.initializeIsCalled = true;
776
777 // At this stage (constructor) no logListener can be here, so this
778 // output will end up in the console
779 logInfos(XmlBlasterLogLevel.TRACE);
780 }
781
782 /**
783 * @see org.xmlBlaster.client.I_XmlBlasterAccess#registerConnectionListener(I_ConnectionStateListener)
784 */
785 public void RegisterConnectionListener(I_ConnectionStateListener connectionListener) {
786 logger(XmlBlasterLogLevel.TRACE, "", "RegisterConnectionListener() is not implemented, TODO!!!");
787 this.connectionListener = connectionListener;
788 }
789
790 private bool logInfoDone = false;
791
792 public void logInfos(XmlBlasterLogLevel level) {
793 if (logInfoDone) return;
794 logInfoDone = true;
795 // At this stage (constructor) no logListener can be here, so this
796 // output will end up in the console
797 logger(level, "", "xmlBlaster C client v" + GetVersion()
798 + " on " + System.Environment.OSVersion.ToString() +
799 # if XMLBLASTER_WINCE
800 " compact framework .net " + System.Environment.Version.ToString());
801 //" deviceId=" + getDeviceUniqueId());
802 # else
803 " .net " + System.Environment.Version.ToString());
804 # endif
805 }
806
807
808 ~PInvokeCE()
809 {
810 if (xa != IntPtr.Zero)
811 freeXmlBlasterAccessUnparsedUnmanagedCE(xa);
812 logger(XmlBlasterLogLevel.TRACE, "", "~PInvokeCE() ...");
813 }
814
815 void check(string methodName)
816 {
817 logger(XmlBlasterLogLevel.TRACE, "", methodName + "() check ...");
818 if (xa == IntPtr.Zero) {
819 logger(XmlBlasterLogLevel.ERROR, "", "Can't process " + methodName + ", xmlBlaster pointer is reset, please create a new instance of PInvokeCE.cs class after a disconnect() call");
820 throw new XmlBlasterException("internal.illegalState", "Can't process " + methodName + ", xmlBlaster pointer is reset, please create a new instance of PInvokeCE.cs class after a disconnect() call");
821 }
822 }
823
824 private delegate void OnLogging(XmlBlasterLogLevel logLevel, string location, string message);
825 private event OnLogging onLogging;
826 public void AddLoggingListener(I_LoggingCallback listener)
827 {
828 if (listener != null)
829 {
830 onLogging += new OnLogging(listener.OnLogging);
831 }
832 }
833 public void RemoveLoggingListener(I_LoggingCallback listener)
834 {
835 if (listener != null)
836 {
837 onLogging -= new OnLogging(listener.OnLogging);
838 }
839 }
840
841 private delegate void OnData(bool read, int currBytesRead, int nbytes);
842 private event OnData onData;
843 public void AddCallbackProgressListener(I_ProgressCallback listener)
844 {
845 if (listener == null) return;
846 if (this.progressUnmanagedFp == null)
847 {
848 this.progressUnmanagedFp = new ProgressUnmanagedFp(this.callbackProgressUnmanaged);
849 this.progressFpForDelegate = Marshal.GetFunctionPointerForDelegate(this.progressUnmanagedFp);
850 xmlBlasterUnmanagedCERegisterProgressListener(xa, this.progressFpForDelegate);
851 }
852 this.onData += new OnData(listener.OnData);
853 }
854
855 public void RemoveCallbackProgressListener(I_ProgressCallback listener)
856 {
857 if (listener != null)
858 {
859 this.onData -= new OnData(listener.OnData);
860 }
861 }
862
863 private delegate string OnUpdate(string cbSessionId, MsgUnitUpdate msgUnit);
864 private event OnUpdate onUpdate;
865 public ConnectReturnQos Connect(string qos, I_Callback listener)
866 {
867 if (!this.initializeIsCalled)
868 Initialize(new Hashtable());
869
870 check("connect");
871 if (listener != null)
872 {
873 onUpdate += new OnUpdate(listener.OnUpdate);
874 }
875 logInfos(XmlBlasterLogLevel.INFO);
876 try
877 {
878 XmlBlasterUnmanagedCEException exception = new XmlBlasterUnmanagedCEException(false);
879 # if CF1 // Compact Framework .net 1.0
880 /*bool bb = */xmlBlasterUnmanagedCEInitialize(xa, IntPtr.Zero, ref exception);
881 # else // Compact Framework 2
882 /*bool bb = */xmlBlasterUnmanagedCEInitialize(xa, updateFpForDelegate, ref exception);
883 # endif
884 checkAndThrow("xmlBlasterUnmanagedCEInitialize", ref exception);
885
886 # if CF1 // Compact Framework .net 1.0
887 IntPtr retP = xmlBlasterUnmanagedCEConnect(xa, stringToUtf8IntPtr(qos), IntPtr.Zero, ref exception);
888 # else // Compact Framework 2
889 IntPtr retP = xmlBlasterUnmanagedCEConnect(xa, stringToUtf8IntPtr(qos), updateFpForDelegate, ref exception);
890 # endif
891 checkAndThrow("xmlBlasterUnmanagedCEConnect", ref exception);
892 string ret = stringFromUtf8IntPtr(retP);
893 //logger(XmlBlasterLogLevel.TRACE, "", "xmlBlasterUnmanagedCEConnect: SUCCESS '" + ret + "'");
894
895 I_ConnectionStateListener li = this.connectionListener;
896 if (li != null) {
897 li.reachedAlive(ConnectionStateEnum.UNDEF, this);
898 }
899
900 return new ConnectReturnQos(ret);
901 }
902 catch (XmlBlasterException e)
903 {
904 throw e;
905 }
906 catch (Exception e)
907 {
908 throw new XmlBlasterException("internal.unknown", "connect failed", e);
909 }
910 }
911
912 public void LeaveServer()
913 {
914 check("LeaveServer");
915 try
916 {
917 IntPtr tmp = xa;
918 xa = IntPtr.Zero;
919 freeXmlBlasterAccessUnparsedUnmanagedCE(tmp);
920 logger(XmlBlasterLogLevel.TRACE, "", "freeXmlBlasterAccessUnparsedUnmanagedCE: SUCCESS freed all resources");
921 }
922 catch (Exception e)
923 {
924 throw new XmlBlasterException("internal.unknown", "LeaveServer failed", e);
925 }
926 }
927
928 /// After calling diconnect() this class is not usable anymore
929 /// you need to create a new instance to connect again
930 public bool Disconnect(string qos)
931 {
932 check("disconnect");
933 XmlBlasterException ex = null;
934 try
935 {
936 XmlBlasterUnmanagedCEException exception = new XmlBlasterUnmanagedCEException(false);
937 bool bb = xmlBlasterUnmanagedCEDisconnect(xa, stringToUtf8IntPtr(qos), ref exception);
938 if (exception.CaughtException())
939 {
940 ex = fillXmlBlasterException(ref exception);
941 // Important logging since we don't throw the exception below
942 logger(XmlBlasterLogLevel.TRACE, "", "xmlBlasterUnmanagedCEDisconnect: Got exception from C: " + ex.ToString());
943 }
944
945 freeXmlBlasterAccessUnparsedUnmanagedCE(xa);
946 xa = IntPtr.Zero;
947 logger(XmlBlasterLogLevel.TRACE, "", "xmlBlasterUnmanagedCEDisconnect: SUCCESS freed all resources");
948
949 //if (ex != null) throw ex;
950 return bb;
951 }
952 catch (XmlBlasterException e)
953 {
954 throw e;
955 }
956 catch (Exception e)
957 {
958 throw new XmlBlasterException("internal.unknown", "disconnect failed", e);
959 }
960 finally {
961 I_ConnectionStateListener li = this.connectionListener;
962 if (li != null) {
963 li.reachedDead(ConnectionStateEnum.ALIVE, this); // TODO: previous state
964 }
965 }
966 }
967
968 private void checkAndThrow(string location, ref XmlBlasterUnmanagedCEException exception)
969 {
970 if (exception.CaughtException())
971 {
972 XmlBlasterException e = fillXmlBlasterException(ref exception);
973 logger(XmlBlasterLogLevel.WARN, "", location + ": errorCode=" + e.ErrorCode);
974 logger(XmlBlasterLogLevel.TRACE, "", location + ": Got exception from C: " + e.ToString());
975
976 if (e.ErrorCode.StartsWith("communication.")) {
977 I_ConnectionStateListener li = this.connectionListener;
978 if (li != null) {
979 li.reachedDead(ConnectionStateEnum.ALIVE, this); // TODO: previous state
980 }
981 }
982
983 throw e;
984 }
985 logger(XmlBlasterLogLevel.TRACE, "", location + ": SUCCESS");
986 }
987
988 public PublishReturnQos Publish(string key, string content, string qos)
989 {
990 return Publish(new MsgUnit(key, content, qos));
991 }
992
993 public PublishReturnQos Publish(MsgUnit msgUnit)
994 {
995 check("publish");
996 try
997 {
998 XmlBlasterUnmanagedCEException exception = new XmlBlasterUnmanagedCEException(false);
999 MsgUnitUnmanagedCEpublish msgUnitUnmanaged = new MsgUnitUnmanagedCEpublish(msgUnit.GetKeyStr(),
1000 msgUnit.GetContent(), msgUnit.GetQosStr());
1001
1002 IntPtr retP = xmlBlasterUnmanagedCEPublish(xa, out msgUnitUnmanaged, ref exception);
1003 checkAndThrow("xmlBlasterUnmanagedCEPublish", ref exception);
1004
1005 string ret = stringFromUtf8IntPtr(retP);
1006 return new PublishReturnQos(ret);
1007 }
1008 catch (XmlBlasterException e)
1009 {
1010 throw e;
1011 }
1012 catch (Exception e)
1013 {
1014 throw new XmlBlasterException("internal.unknown", "publish failed", e);
1015 }
1016 }
1017
1018 public void PublishOneway(MsgUnit[] msgUnitArr)
1019 {
1020 check("publishOneway");
1021 if (msgUnitArr.Length < 1)
1022 return;
1023 IntPtr arrP = IntPtr.Zero;
1024 try
1025 {
1026 IntPtr current = arrP;
1027 for (int i=0; i<msgUnitArr.Length; i++) {
1028 MsgUnitUnmanagedCEpublish msgUnitUnmanaged = new MsgUnitUnmanagedCEpublish(msgUnitArr[i].GetKeyStr(),
1029 msgUnitArr[i].GetContent(), msgUnitArr[i].GetQosStr());
1030 if (i == 0) {
1031 int len = Marshal.SizeOf(msgUnitUnmanaged);
1032 arrP = Marshal.AllocHGlobal(msgUnitArr.Length * len);
1033 current = arrP;
1034 }
1035 Marshal.StructureToPtr(msgUnitUnmanaged, current, false);
1036 current = (IntPtr)((long)current + Marshal.SizeOf(msgUnitUnmanaged));
1037 }
1038 XmlBlasterUnmanagedCEException exception = new XmlBlasterUnmanagedCEException(false);
1039 xmlBlasterUnmanagedCEPublishOneway(xa, arrP, msgUnitArr.Length, ref exception);
1040 checkAndThrow("xmlBlasterUnmanagedCEPublishOneway", ref exception);
1041 logger(XmlBlasterLogLevel.TRACE, "", "publishOneway: SUCCESS");
1042 }
1043 catch (XmlBlasterException e)
1044 {
1045 throw e;
1046 }
1047 catch (Exception e)
1048 {
1049 throw new XmlBlasterException("internal.unknown", "publishOneway failed", e);
1050 }
1051 finally {
1052 if (arrP != IntPtr.Zero) Marshal.FreeHGlobal(arrP);
1053 }
1054 }
1055
1056 public SubscribeReturnQos Subscribe(string key, string qos)
1057 {
1058 check("subscribe");
1059 try
1060 {
1061 XmlBlasterUnmanagedCEException exception = new XmlBlasterUnmanagedCEException(false);
1062 IntPtr retP = xmlBlasterUnmanagedCESubscribe(xa, stringToUtf8IntPtr(key),
1063 stringToUtf8IntPtr(qos), ref exception);
1064 checkAndThrow("xmlBlasterUnmanagedCESubscribe", ref exception);
1065 string ret = stringFromUtf8IntPtr(retP);
1066 logger(XmlBlasterLogLevel.TRACE, "", ret);
1067 return new SubscribeReturnQos(ret);
1068 }
1069 catch (XmlBlasterException e)
1070 {
1071 throw e;
1072 }
1073 catch (Exception e)
1074 {
1075 throw new XmlBlasterException("internal.unknown", "subscribe failed", e);
1076 }
1077 }
1078
1079 public UnSubscribeReturnQos[] UnSubscribe(string key, string qos)
1080 {
1081 check("unSubscribe");
1082 try
1083 {
1084 XmlBlasterUnmanagedCEException exception = new XmlBlasterUnmanagedCEException(false);
1085 int size;
1086 IntPtr outArray = new IntPtr();
1087 xmlBlasterUnmanagedCEUnSubscribe(xa, stringToUtf8IntPtr(key), stringToUtf8IntPtr(qos), ref exception, out size, out outArray);
1088 checkAndThrow("xmlBlasterUnmanagedCEUnSubcribe", ref exception);
1089 if (size == 0)
1090 {
1091 logger(XmlBlasterLogLevel.TRACE, "", "xmlBlasterUnmanagedCEUnSubcribe: Done (no topics found)");
1092 return new UnSubscribeReturnQos[0];
1093 }
1094 UnSubscribeReturnQos[] retQosArr = new UnSubscribeReturnQos[size];
1095 IntPtr current = outArray;
1096 for (int i = 0; i < size; i++)
1097 {
1098 StringArr stringArr = new StringArr();
1099 Marshal.PtrToStructure(current, stringArr);
1100 current = (IntPtr)((long)current + Marshal.SizeOf(stringArr));
1101 string ret = stringFromUtf8IntPtr(stringArr.str);
1102 retQosArr[i] = new UnSubscribeReturnQos(ret);
1103 }
1104 xmlBlasterUnmanagedCEFreePP(out outArray);
1105 return retQosArr;
1106 }
1107 catch (XmlBlasterException e)
1108 {
1109 throw e;
1110 }
1111 catch (Exception e)
1112 {
1113 throw new XmlBlasterException("internal.unknown", "unSubscribe failed", e);
1114 }
1115 }
1116
1117 public EraseReturnQos[] Erase(string key, string qos)
1118 {
1119 check("erase");
1120 try
1121 {
1122 XmlBlasterUnmanagedCEException exception = new XmlBlasterUnmanagedCEException(false);
1123 int size;
1124 IntPtr outArray = new IntPtr();
1125 xmlBlasterUnmanagedCEErase(xa, stringToUtf8IntPtr(key), stringToUtf8IntPtr(qos), ref exception, out size, out outArray);
1126 checkAndThrow("xmlBlasterUnmanagedCEErase", ref exception);
1127 if (size == 0)
1128 {
1129 logger(XmlBlasterLogLevel.TRACE, "", "xmlBlasterUnmanagedCEErase: Done (no topics found)");
1130 return new EraseReturnQos[0];
1131 }
1132
1133 EraseReturnQos[] retQosArr = new EraseReturnQos[size];
1134 IntPtr current = outArray;
1135 for (int i = 0; i < size; i++)
1136 {
1137 StringArr stringArr = new StringArr();
1138 Marshal.PtrToStructure(current, stringArr);
1139 current = (IntPtr)((long)current + Marshal.SizeOf(stringArr));
1140 string ret = stringFromUtf8IntPtr(stringArr.str);
1141 retQosArr[i] = new EraseReturnQos(ret);
1142 }
1143 //logger(XmlBlasterLogLevel.TRACE, "", "xmlBlasterUnmanagedCEErase: FREEING WRONG POINTER??");
1144 xmlBlasterUnmanagedCEFreePP(out outArray);
1145 return retQosArr;
1146 }
1147 catch (XmlBlasterException e)
1148 {
1149 throw e;
1150 }
1151 catch (Exception e)
1152 {
1153 throw new XmlBlasterException("internal.unknown", "erase failed", e);
1154 }
1155 }
1156
1157 public MsgUnitGet[] Get(string key, string qos)
1158 {
1159 check("get");
1160 try
1161 {
1162 XmlBlasterUnmanagedCEException exception = new XmlBlasterUnmanagedCEException(false);
1163 int size;
1164 IntPtr outArray = new IntPtr();
1165 xmlBlasterUnmanagedCEGet(xa, stringToUtf8IntPtr(key), stringToUtf8IntPtr(qos),
1166 ref exception, out size, out outArray);
1167 checkAndThrow("xmlBlasterUnmanagedCEGet", ref exception);
1168 MsgUnitGet[] msgUnitArr = new MsgUnitGet[size];
1169 IntPtr current = outArray;
1170 for (int i = 0; i < size; i++)
1171 {
1172 logger(XmlBlasterLogLevel.TRACE, "", "xmlBlasterUnmanagedCEGet: parsing #" + i);
1173 MsgUnitUnmanagedCEget msgUnitUnmanaged = new MsgUnitUnmanagedCEget();
1174 Marshal.PtrToStructure(current, msgUnitUnmanaged);
1175 //Console.WriteLine("msgUnitUnmanaged.contentLen=" + msgUnitUnmanaged.contentLen + " sizeof="+Marshal.SizeOf(msgUnitUnmanaged));
1176 current = (IntPtr)((long)current + Marshal.SizeOf(msgUnitUnmanaged));
1177 // The getters free the memory in the C DLL:
1178 msgUnitArr[i] = new MsgUnitGet(
1179 msgUnitUnmanaged.getKey(), msgUnitUnmanaged.getContent(), msgUnitUnmanaged.getQos());
1180 msgUnitUnmanaged.getResponseQos(); // dummy call to free memory in C DLL
1181 }
1182 //logger(XmlBlasterLogLevel.TRACE, "", "xmlBlasterUnmanagedCEGet: freeing now IntPtr SHOULD IT BE *outArray???");
1183 xmlBlasterUnmanagedCEFreePP(out outArray);
1184 return msgUnitArr;
1185 }
1186 catch (XmlBlasterException e)
1187 {
1188 throw e;
1189 }
1190 catch (Exception e)
1191 {
1192 throw new XmlBlasterException("internal.unknown", "get failed", e);
1193 }
1194 }
1195
1196 public string Ping(string qos)
1197 {
1198 check("ping");
1199 try
1200 {
1201 XmlBlasterUnmanagedCEException exception = new XmlBlasterUnmanagedCEException(false);
1202 IntPtr retP = xmlBlasterUnmanagedCEPing(xa, stringToUtf8IntPtr(qos), ref exception);
1203 checkAndThrow("xmlBlasterUnmanagedCEPing", ref exception);
1204 string ret = stringFromUtf8IntPtr(retP);
1205 return ret;
1206 }
1207 catch (XmlBlasterException e)
1208 {
1209 throw e;
1210 }
1211 catch (Exception e)
1212 {
1213 throw new XmlBlasterException("internal.unknown", "ping failed", e);
1214 }
1215 }
1216
1217 public bool IsConnected()
1218 {
1219 if (xa == IntPtr.Zero) return false;
1220 try
1221 {
1222 bool bb = xmlBlasterUnmanagedCEIsConnected(xa);
1223 logger(XmlBlasterLogLevel.TRACE, "", "xmlBlasterUnmanagedCEIsConnected: SUCCESS '" + bb + "'");
1224 return bb;
1225 }
1226 catch (XmlBlasterException e)
1227 {
1228 throw e;
1229 }
1230 catch (Exception e)
1231 {
1232 throw new XmlBlasterException("internal.unknown", "isConnected failed", e);
1233 }
1234 }
1235
1236 public string GetVersion()
1237 {
1238 IntPtr retP = xmlBlasterUnmanagedCEVersion();
1239 return stringFromUtf8IntPtr(retP);
1240 }
1241
1242 public string GetUsage()
1243 {
1244 IntPtr retP = xmlBlasterUnmanagedCEUsage();
1245 return stringFromUtf8IntPtr(retP);
1246 }
1247
1248 public string GetEmeiId() {
1249 # if XMLBLASTER_WINCE
1250 try {
1251 IntPtr intPtr = getXmlBlasterEmei();
1252 if (intPtr == IntPtr.Zero)
1253 return null;
1254 byte[] bytes = byteArrayFromIntPtr(intPtr, -1, true);
1255 string emeiId = toHexString(bytes);
1256 return emeiId;
1257 }
1258 catch (Exception e) {
1259 logger(XmlBlasterLogLevel.WARN, "", "getEmeiId() is not supported on this platform: " + e.ToString());
1260 return null;
1261 }
1262 # else
1263 return null;
1264 # endif
1265 }
1266
1267 public string GetDeviceUniqueId() {
1268 # if XMLBLASTER_WINCE
1269 byte[] bytes = GetDeviceID("xmlBlasterClient");
1270 if (bytes == null) return null;
1271 string deviceId = toHexString(bytes);
1272 //{// Remove again
1273 // throw new XmlBlasterException("bla", "My deviceId=" + deviceId);
1274 //}
1275 return deviceId;
1276 # else
1277 return null;
1278 # endif
1279 }
1280
1281 public static string toHexString(byte[] bytes) {
1282 if (bytes == null) return null;
1283 StringBuilder temp = new StringBuilder();
1284 for (int i=0; i<bytes.Length; i++)
1285 temp.Append(bytes[i].ToString("X2")); // hex view
1286 //temp.Append(bytes[i].ToString("D3")).Append(" "); // Decimal view
1287 return temp.ToString();
1288 }
1289
1290 #if XMLBLASTER_WINCE
1291 /*
1292 HRESULT GetDeviceUniqueID(
1293 LPBYTE pbApplicationData,
1294 DWORD cbApplictionData,
1295 DWORD dwDeviceIDVersion,
1296 LPBYTE pbDeviceIDOutput,
1297 DWORD* pcbDeviceIDOutput
1298 );
1299 */
1300 //http://blogs.msdn.com/windowsmobile/archive/2006/01/09/510997.aspx#514959
1301 [DllImport("coredll.dll")]
1302 private extern static int GetDeviceUniqueID([In, Out] byte[] appdata,
1303 int cbApplictionData,
1304 int dwDeviceIDVersion,
1305 [In, Out] byte[] deviceIDOuput,
1306 out uint pcbDeviceIDOutput);
1307
1308 /// Works only on Windows Mobile 5 and above
1309 private byte[] GetDeviceID(string AppString)
1310 {
1311 // Call the GetDeviceUniqueID
1312 byte[] AppData = new byte[AppString.Length];
1313 for (int count = 0; count < AppString.Length; count++)
1314 AppData[count] = (byte)AppString[count];
1315
1316 int appDataSize = AppData.Length;
1317 byte[] DeviceOutput = new byte[20];
1318 uint SizeOut = 20;
1319
1320 try {
1321 GetDeviceUniqueID(AppData, appDataSize, 1, DeviceOutput, out SizeOut);
1322 }
1323 catch (Exception e) {
1324 logger(XmlBlasterLogLevel.WARN, "", "GetDeviceUniqueID() is not supported on this platform");
1325 logger(XmlBlasterLogLevel.TRACE, "", "GetDeviceUniqueID() is not supported on this platform: " + e.ToString());
1326 return null;
1327 }
1328
1329 if (SizeOut == 0)
1330 return null;
1331
1332 return DeviceOutput;
1333 }
1334 #endif
1335
1336 /* From news group 2007-03-01
1337 // support@NOdroopySPAMeyes.com
1338 // microsoft.public.dotnet.framework.compactframework
1339 #region DeviceId support
1340
1341 [DllImport("coredll.dll")]
1342
1343 private static extern bool KernelIoControl(Int32 IoControlCode, IntPtr
1344
1345 InputBuffer, Int32 InputBufferSize, byte[] OutputBuffer, Int32
1346
1347 OutputBufferSize, ref Int32 BytesReturned);
1348
1349
1350
1351
1352
1353 private static Int32 FILE_DEVICE_HAL = 0x00000101;
1354
1355 private static Int32 FILE_ANY_ACCESS = 0x0;
1356
1357 private static Int32 METHOD_BUFFERED = 0x0;
1358
1359 private static Int32 IOCTL_HAL_GET_DEVICEID =
1360
1361 ((FILE_DEVICE_HAL) << 16) | ((FILE_ANY_ACCESS) << 14)
1362
1363 | ((21) << 2) | (METHOD_BUFFERED);
1364
1365 private static string GetDeviceID()
1366
1367 {
1368
1369 byte[] OutputBuffer = new byte[256];
1370
1371 Int32 OutputBufferSize, BytesReturned;
1372
1373 OutputBufferSize = OutputBuffer.Length;
1374
1375 BytesReturned = 0;
1376
1377 // Call KernelIoControl passing the previously defined
1378
1379 // IOCTL_HAL_GET_DEVICEID parameter
1380
1381 // We donĀ't need to pass any input buffers to this call
1382
1383 // so InputBuffer and InputBufferSize are set to their null
1384
1385 // values
1386
1387 bool retVal = KernelIoControl(IOCTL_HAL_GET_DEVICEID, IntPtr.Zero, 0,
1388
1389 OutputBuffer,
1390
1391 OutputBufferSize,
1392
1393 ref BytesReturned);
1394
1395 // If the request failed, exit the method now
1396
1397 if (retVal == false)
1398
1399 {
1400
1401 return null;
1402
1403 }
1404
1405 // Examine the OutputBuffer byte array to find the start of the
1406
1407 // Preset ID and Platform ID, as well as the size of the
1408
1409 // PlatformID.
1410
1411 // PresetIDOffset - The number of bytes the preset ID is offset
1412
1413 // from the beginning of the structure
1414
1415 // PlatformIDOffset - The number of bytes the platform ID is
1416
1417 // offset from the beginning of the structure
1418
1419 // PlatformIDSize - The number of bytes used to store the
1420
1421 // platform ID
1422
1423 // Use BitConverter.ToInt32() to convert from byte[] to int
1424
1425 Int32 PresetIDOffset = BitConverter.ToInt32(OutputBuffer, 4);
1426
1427 Int32 PlatformIDOffset = BitConverter.ToInt32(OutputBuffer, 0xc);
1428
1429 Int32 PlatformIDSize = BitConverter.ToInt32(OutputBuffer, 0x10);
1430
1431 // Convert the Preset ID segments into a string so they can be
1432
1433 // displayed easily.
1434
1435 StringBuilder sb = new StringBuilder();
1436
1437 sb.Append(String.Format("{0:X8}-{1:X4}-{2:X4}-{3:X4}-",
1438
1439 BitConverter.ToInt32(OutputBuffer, PresetIDOffset),
1440
1441 BitConverter.ToInt16(OutputBuffer, PresetIDOffset + 4),
1442
1443 BitConverter.ToInt16(OutputBuffer, PresetIDOffset + 6),
1444
1445 BitConverter.ToInt16(OutputBuffer, PresetIDOffset + 8)));
1446
1447 // Break the Platform ID down into 2-digit hexadecimal numbers
1448
1449 // and append them to the Preset ID. This will result in a
1450
1451 // string-formatted Device ID
1452
1453 for (int i = PlatformIDOffset;
1454
1455 i < PlatformIDOffset + PlatformIDSize;
1456
1457 i++)
1458
1459 {
1460
1461 sb.Append(String.Format("{0:X2}", OutputBuffer[i]));
1462
1463 }
1464
1465 // return the Device ID string
1466
1467 return sb.ToString();
1468
1469 }
1470
1471 #endregion
1472 */
1473
1474 } // class PInvokeCE
1475 } // namespace
syntax highlighted by Code2HTML, v. 0.9.1