socket/XmlBlasterUnmanagedCE.c

Go to the documentation of this file.
00001 /*----------------------------------------------------------------------------
00002 Name:      XmlBlasterUnmanagedCE.c
00003 Project:   xmlBlaster.org
00004 Copyright: xmlBlaster.org, see xmlBlaster-LICENSE file
00005 Comment:   See XmlBlasterUnmanagedCE.h
00006            Access C dll from C# on Windows CE with P/Invoke
00007 Todo:      Callback function (update from Dll to C#)
00008 Author:    "Marcel Ruff" <xmlBlaster@marcelruff.info>
00009 See:       http://www.xmlblaster.org/xmlBlaster/doc/requirements/protocol.socket.html
00010 -----------------------------------------------------------------------------*/
00011 #include <string.h> /* memset */
00012 #include <stdio.h>  /* printf */
00013 #include <XmlBlasterUnmanagedCE.h>
00014 #ifndef WINCE
00015 #  include <stdarg.h>
00016 #  include <locale.h> /* setlocal() */
00017 #endif
00018 
00019 #ifdef __cplusplus
00020 #       define XBFORCE_EXTERNC extern "C"
00021 #else
00022 #       define XBFORCE_EXTERNC
00023 #endif
00024 
00025 static const bool freeIt = true;
00026 
00027 /*
00028  We should avoid C++ code as the name mangling makes difficulties,
00029  so we force C code here.
00030  See: http://www.opennetcf.org/Forums/topic.asp?TOPIC_ID=255
00031 */
00032 
00033 static void myLogger(void *logUserP, 
00034                      XMLBLASTER_LOG_LEVEL currLevel,
00035                      XMLBLASTER_LOG_LEVEL level,
00036                      const char *location, const char *fmt, ...);
00037 
00038 static void myLogger(void *logUserP, 
00039                      XMLBLASTER_LOG_LEVEL currLevel,
00040                      XMLBLASTER_LOG_LEVEL level,
00041                      const char *location, const char *fmt, ...)
00042 {
00043    /* Guess we need no more than 200 bytes. */
00044    int n, size = 200;
00045    char *p = 0;
00046    va_list ap;
00047    int32_t lvl = (int32_t)level;
00048    XmlBlasterUnmanagedCELoggerFp managedLoggerFp = (XmlBlasterUnmanagedCELoggerFp)logUserP;
00049 
00050 
00051    if (managedLoggerFp == 0)
00052       return;
00053 
00054    if (level > currLevel) { /* XMLBLASTER_LOG_ERROR, XMLBLASTER_LOG_WARN, XMLBLASTER_LOG_INFO, XMLBLASTER_LOG_TRACE */
00055       return;
00056    }
00057    if ((p = (char *)malloc (size)) == NULL)
00058       return;
00059 
00060    for (;;) {
00061       /* Try to print in the allocated space. */
00062       va_start(ap, fmt);
00063       n = VSNPRINTF(p, size, fmt, ap); /* UNIX: vsnprintf(), WINDOWS: _vsnprintf() */
00064       va_end(ap);
00065       /* If that worked, print the string to console. */
00066       if (n > -1 && n < size) {
00067          /*printf("{%s-%s-%s} [%s] %s\n",
00068                    __DATE__, __TIME__, getLogLevelStr(level), location, p);*/
00069          /* Call now the C# logger XmlBlasterUnmanagedCELoggerFp */
00070 
00071          (*managedLoggerFp)(lvl, location, p);
00072          
00073          /* The C# code does not free 'p' during its UNICODE marshalling 
00074             with byteArrayFromIntPtr(false) -> no xmlBlasterUnmanagedCEFree() */
00075          free(p);
00076          
00077          return;
00078       }
00079       /* Else try again with more space. */
00080       if (n > -1)    /* glibc 2.1 */
00081          size = n+1; /* precisely what is needed */
00082       else           /* glibc 2.0 */
00083          size *= 2;  /* twice the old size */
00084       if ((p = (char *)realloc (p, size)) == NULL) {
00085          return;
00086       }
00087    }
00088 }
00089 
00090 /* extern "C" __declspec (dllexport) */
00091 XBFORCE_EXTERNC Dll_Export void xmlBlasterUnmanagedCERegisterLogger(struct XmlBlasterAccessUnparsed *xa,
00092                            XmlBlasterUnmanagedCELoggerFp logger) {
00093    /*MessageBox(NULL, L"Entering xmlBlasterUnmanagedCERegisterLogger", _T("Unmanaged"), MB_OK);*/
00094    /*printf("dll: Register logger\n");*/
00095    if (logger != 0) {
00096       /* Register our own logging function */
00097       xa->log = myLogger;
00098       /* Pass a pointer which we can use in myLogger() again */
00099       xa->logUserP = (void*)logger;
00100    }
00101    else { /* unregister */
00102       xa->log = 0;
00103       xa->logUserP = 0;
00104    }
00105    /*xa->log(xa->logUserP, xa->logLevel, XMLBLASTER_LOG_ERROR, __FILE__, "Testing logging output only");*/
00106 }
00107 
00108 
00109 static void callbackProgressListener(void *userP, const size_t currBytesRead, const size_t nbytes);
00115 static void callbackProgressListener(void *userP, const size_t currBytesRead, const size_t nbytes) {
00116    XmlBlasterUnmanagedCECallbackProgressListenerFp *fp = (XmlBlasterUnmanagedCECallbackProgressListenerFp *)userP;
00117    if (fp != 0) {
00118       int32_t curr = (int32_t)currBytesRead;
00119       int32_t n = (int32_t)nbytes;
00120       printf("C-DLL: entering callbackProgressListener(fp=%ld) %d/%d\n", (long)fp, curr, n);
00121       (*fp)(curr, n);
00122       printf("C-DLL: done callbackProgressListener(fp=%ld) %d/%d\n", (long)fp, curr, n);
00123    }
00124 }
00128 XBFORCE_EXTERNC Dll_Export void xmlBlasterUnmanagedCERegisterProgressListener(
00129    struct XmlBlasterAccessUnparsed *xa,
00130    XmlBlasterUnmanagedCECallbackProgressListenerFp csharpProgressListenerFp) {
00131 
00132    if (xa && xa->callbackP != 0) {
00133       xa->callbackP->readFromSocket.numReadUserP = (void*)csharpProgressListenerFp;
00134       if (callbackProgressListener != 0) {
00135          printf("C-DLL: doing xmlBlasterUnmanagedCERegisterProgressListener(csharpProgressListenerFp=%ld)\n", (long)csharpProgressListenerFp);
00136          xa->callbackP->readFromSocket.numReadFuncP = callbackProgressListener;
00137       }
00138       else {
00139          xa->callbackP->readFromSocket.numReadFuncP = 0; /* Dangerous: not thread safe, TODO: Add a mutex */
00140       }
00141    }
00142 }
00143 
00149 XBFORCE_EXTERNC extern char *xmlBlasterUnmanagedCEMalloc(int32_t size) {
00150    /*printf("dll: xmlBlasterUnmanagedCEMalloc(size=%d)\n", size);*/
00151    if (size > 0)
00152       return (char *)malloc(size*sizeof(char));
00153    return (char *)0;
00154 }
00155 
00160 XBFORCE_EXTERNC extern void xmlBlasterUnmanagedCEFree(char *p)  {
00161    /*if (p!=0)
00162       printf("dll: xmlBlasterUnmanagedCEFree size=%d:\n%s\n", strlen(p), p);*/ /* dangeraous for none strings like IntPtr */
00163    xmlBlasterFree(p);
00164 }
00165 
00172 XBFORCE_EXTERNC extern void xmlBlasterUnmanagedCEFreePP(char **pp)  {
00173    if (pp==0)
00174       return;
00175    else {
00176       char *p = *pp;
00177       /*printf("dll: xmlBlasterUnmanagedCEFreePP('%s')\n", ((p!=(char *)0)?p:""));*/
00178       xmlBlasterFree(p);
00179    }
00180 }
00181 
00186 XBFORCE_EXTERNC static void convert(XmlBlasterException *in, XmlBlasterUnmanagedCEException *out) {
00187    if (*in->errorCode != 0) {
00188       out->errorCode = strcpyAlloc(in->errorCode);
00189       out->message = strcpyAlloc(in->message);
00190       out->remote = in->remote;
00191    }
00192    else {
00193       out->errorCode = 0;
00194    }   
00195 }
00196 
00197 XBFORCE_EXTERNC extern void xmlBlasterUnmanagedCEExceptionFree(XmlBlasterUnmanagedCEException *ex) {
00198    if (ex == 0) return;
00199    xmlBlasterFree(ex->errorCode);
00200    ex->errorCode = 0;
00201    xmlBlasterFree(ex->message);
00202    ex->message = 0;
00203    ex->remote = 0;
00204 }
00205 
00206 
00211 XBFORCE_EXTERNC static XMLBLASTER_C_bool interceptUpdate(MsgUnitArr *msgUnitArr, void *userData, XmlBlasterException *exception) {
00212    size_t i;
00213    XmlBlasterUnmanagedCEException unmanagedException;
00214    XMLBLASTER_C_bool retVal = true;
00215    int32_t isOneway = 0;
00216    /*MessageBox(NULL, L"Entering interceptUpdate0", _T("Unmanaged"), MB_OK);*/
00217 
00218    XmlBlasterAccessUnparsed *xa = (XmlBlasterAccessUnparsed *)userData;
00219    XmlBlasterUnmanagedCEUpdateFp unmanagedUpdate = (XmlBlasterUnmanagedCEUpdateFp)(xa->userFp);
00220 
00221    if (xa->logLevel>=XMLBLASTER_LOG_TRACE)
00222       xa->log(xa->logUserP, xa->logLevel, XMLBLASTER_LOG_TRACE, __FILE__, "Got update message");
00223    
00224    if (userData != 0) ;  /* Supress compiler warning */
00225    if (unmanagedUpdate == 0) return false;
00226    
00227    /*memset(&unmanagedException, 0, sizeof(struct XmlBlasterUnmanagedCEException));*/
00228    unmanagedException.remote = false;
00229    unmanagedException.errorCode = (char)0;
00230    unmanagedException.message = (char)0;
00231    
00232    isOneway = msgUnitArr->isOneway;
00233    for (i=0; i<msgUnitArr->len; i++) {
00234       const char *cbSessionId = strcpyAlloc(msgUnitArr->secretSessionId);
00235       /*
00236       char *xml = messageUnitToXml(&msgUnitArr->msgUnitArr[i]);
00237       printf("[client] CALLBACK update(): Asynchronous message update arrived:%s\n",
00238              xml);
00239       xmlBlasterFree(xml);
00240       
00241       printf("XmlBlasterUnmanaged.c: before update() %d\n", (int)msgUnitArr->len);
00242       */
00243       
00244       if (xa->logLevel>=XMLBLASTER_LOG_TRACE) xa->log(xa->logUserP, xa->logLevel, XMLBLASTER_LOG_TRACE, __FILE__, "Got update, calling C# ...");
00245 
00246       /* Call C# ..., it may allocate errorCode */
00247       unmanagedUpdate(cbSessionId, &msgUnitArr->msgUnitArr[i], isOneway, &unmanagedException);
00248 
00249       if (xa->logLevel>=XMLBLASTER_LOG_TRACE) xa->log(xa->logUserP, xa->logLevel, XMLBLASTER_LOG_TRACE, __FILE__, "Got update, calling C# DONE");
00250 
00251       if (unmanagedException.errorCode != 0) {
00252          /* catch first exception set and return */
00253          strncpy0(exception->errorCode, unmanagedException.errorCode, EXCEPTIONSTRUCT_ERRORCODE_LEN);
00254          if (unmanagedException.message != 0)
00255             strncpy0(exception->message, unmanagedException.message, EXCEPTIONSTRUCT_MESSAGE_LEN);
00256          exception->remote = unmanagedException.remote;
00257          xmlBlasterUnmanagedCEExceptionFree(&unmanagedException);
00258          msgUnitArr->msgUnitArr[i].responseQos = 0;
00259          xa->log(xa->logUserP, xa->logLevel, XMLBLASTER_LOG_WARN, __FILE__, "Rethrowing exception from C# '%s' '%s'", exception->errorCode, exception->message);
00260          retVal = false;
00261       }
00262       else {
00263          msgUnitArr->msgUnitArr[i].responseQos = strcpyAlloc("<qos><state id='OK'/></qos>");
00264          /* Return QoS: Everything is OK */
00265       }
00266    }
00267    
00268    return retVal;
00269 }
00270 
00271 /*
00272  * We take a clone of argv, and not free your argv (crashes for some reason if we free it here)
00273  * @paran argc
00274  * @param argv [0] contains the exe name, [1] the first argument, etc.
00275  *   "Hello.exe" "-dispatch/connection/plugin/socket/hostname" "192.168.1.2"
00276  * @return the XmlBlasterAccessUnparsed handle
00277  */
00278 XBFORCE_EXTERNC Dll_Export XmlBlasterAccessUnparsed *getXmlBlasterAccessUnparsedUnmanagedCE(int argc, char** argv){
00279    int i=0;
00280    XmlBlasterAccessUnparsed *xa;
00281    const char ** ptr = (const char **)malloc(argc*sizeof(char *));
00282    for (i=0; i<argc; ++i) {
00283       ptr[i] = strcpyAlloc(argv[i]);
00284       /*printf("dll: getAccess '%s'\n", argv[i]);*/
00285       /*if (freeIt) { xmlBlasterFree(argv[i]); argv[i] = 0; }*/
00286    }
00287    /*if (freeIt) { xmlBlasterFree((char *)argv); }*/
00288    xa = getXmlBlasterAccessUnparsed(argc, ptr);
00289    /*xa->userObject = ...; // Transports something to the interceptUpdate() method*/
00290    return xa;
00291 }
00292 
00293 XBFORCE_EXTERNC Dll_Export void freeXmlBlasterAccessUnparsedUnmanagedCE(XmlBlasterAccessUnparsed *xmlBlasterAccess) {
00294    if (xmlBlasterAccess != 0) {
00295       int i;
00296       for (i=0; i<xmlBlasterAccess->argc; ++i)
00297          free((void*)xmlBlasterAccess->argv[i]);
00298       free((void*)xmlBlasterAccess->argv);
00299       freeXmlBlasterAccessUnparsed(xmlBlasterAccess);
00300    }
00301 }
00302 
00303 XBFORCE_EXTERNC Dll_Export bool xmlBlasterUnmanagedCEInitialize(struct XmlBlasterAccessUnparsed *xa,
00304             XmlBlasterUnmanagedCEUpdateFp update, XmlBlasterUnmanagedCEException *exception) {
00305    XmlBlasterException e;
00306    bool ret = false;
00307    xa->userFp = (XmlBlasterAccessGenericFp)update;
00308    ret = xa->initialize(xa, interceptUpdate, &e);
00309    convert(&e, exception);
00310    return ret; 
00311 }
00312 
00316 XBFORCE_EXTERNC Dll_Export char *xmlBlasterUnmanagedCEConnect(struct XmlBlasterAccessUnparsed *xa,
00317                            char *qos, XmlBlasterUnmanagedCEUpdateFp update, XmlBlasterUnmanagedCEException *exception) {
00318    XmlBlasterException e;
00319    char *ret = 0;
00320    /*MessageBox(NULL, L"Entering xmlBlasterUnmanagedCEConnect", _T("Unmanaged"), MB_OK);*/
00321    if (update != 0)
00322       xa->userFp = (XmlBlasterAccessGenericFp)update;
00323    ret = xa->connect(xa, qos, interceptUpdate, &e);
00324    convert(&e, exception);
00325    if (freeIt) { xmlBlasterFree(qos); qos=0; }
00326    return ret; 
00327 }
00328 
00332 XBFORCE_EXTERNC Dll_Export extern bool xmlBlasterUnmanagedCEDisconnect(struct XmlBlasterAccessUnparsed *xa,
00333                            char * qos, XmlBlasterUnmanagedCEException *exception) {
00334    XmlBlasterException e;
00335    bool ret = xa->disconnect(xa, qos, &e);
00336    convert(&e, exception);
00337    if (freeIt) { xmlBlasterFree(qos); qos=0; }
00338    return ret; 
00339 }
00340 
00341 XBFORCE_EXTERNC Dll_Export extern char *xmlBlasterUnmanagedCEPublish(struct XmlBlasterAccessUnparsed *xa,
00342                 MsgUnitUnmanagedCEpublish *msgUnitUnmanaged, XmlBlasterUnmanagedCEException *exception) {
00343    XmlBlasterException e;
00344    char *ret = xa->publish(xa, msgUnitUnmanaged, &e);
00345    convert(&e, exception);
00346    if (freeIt) freeMsgUnitData(msgUnitUnmanaged);
00347    return ret; 
00348 }
00349 
00350 XBFORCE_EXTERNC Dll_Export extern QosArr *xmlBlasterUnmanagedCEPublishArr(struct XmlBlasterAccessUnparsed *xa, MsgUnitArr *msgUnitArr, XmlBlasterUnmanagedCEException *exception) {
00351    XmlBlasterException e;
00352    QosArr *ret = xa->publishArr(xa, msgUnitArr, &e);
00353    convert(&e, exception);
00354    return ret; 
00355 }
00356 
00357 XBFORCE_EXTERNC Dll_Export extern void xmlBlasterUnmanagedCEPublishOneway(struct XmlBlasterAccessUnparsed *xa, void *msgUnitArr, int length, XmlBlasterUnmanagedCEException *exception) {
00358    XmlBlasterException e;
00359    MsgUnitArr arr;
00360    /*printf("C: xmlBlasterUnmanagedCEPublishOneway %d\n", length);*/
00361    arr.isOneway = true;
00362    arr.len = length;
00363    arr.msgUnitArr = (MsgUnit*)msgUnitArr;
00364    *arr.secretSessionId = 0;
00365    xa->publishOneway(xa, &arr, &e);
00366    convert(&e, exception);
00367    if (freeIt) {
00368       size_t i;
00369       for (i=0; i<arr.len; i++) {
00370          freeMsgUnitData(&arr.msgUnitArr[i]);
00371       }
00372       /*free(msgUnitArr.msgUnitArr); is memory from C# IntPtr*/
00373    }
00374 }
00375 
00379 XBFORCE_EXTERNC Dll_Export extern char *xmlBlasterUnmanagedCESubscribe(struct XmlBlasterAccessUnparsed *xa, char *key, char *qos, XmlBlasterUnmanagedCEException *exception) {
00380    XmlBlasterException e;
00381    char *ret = xa->subscribe(xa, key, qos, &e);
00382    convert(&e, exception);
00383    if (freeIt) { xmlBlasterFree(key); key=0; }
00384    if (freeIt) { xmlBlasterFree(qos); qos=0; }
00385    return ret; 
00386 }
00387 
00388 XBFORCE_EXTERNC Dll_Export void xmlBlasterUnmanagedCEUnSubscribe(struct XmlBlasterAccessUnparsed *xa,
00389    char * key, char * qos, XmlBlasterUnmanagedCEException *exception, uint32_t* pSize, XmlBlasterUnmanagedCEStringArr** ppStruct) {
00390    XmlBlasterException e;
00391    QosArr *ret = 0;
00392    initializeXmlBlasterException(&e);
00393    ret = xa->unSubscribe(xa, key, qos, &e);
00394    convert(&e, exception);
00395    if (freeIt) { xmlBlasterFree(key); key=0; }
00396    if (freeIt) { xmlBlasterFree(qos); qos=0; }
00397    if (*e.errorCode != 0) {
00398       /*printf("C: Caught exception in unSubscribe errorCode=%s, message=%s\n", e.errorCode, e.message);*/
00399       if (ret) freeQosArr(ret);
00400       return;
00401    }
00402    if (ret) {
00403       size_t i;
00404       XmlBlasterUnmanagedCEStringArr* pCurStruct = 0;
00405       const uint32_t cArraySize = ret->len;
00406       *pSize = cArraySize;
00407       *ppStruct = (XmlBlasterUnmanagedCEStringArr*)malloc( cArraySize * sizeof( XmlBlasterUnmanagedCEStringArr ));
00408       pCurStruct = *ppStruct;
00409       for (i=0; i<ret->len; i++, pCurStruct++) {
00410          /*printf("C: Unsubscribe success, returned status is '%s'\n", ret->qosArr[i]);*/
00411          pCurStruct->str = strcpyAlloc(ret->qosArr[i]);
00412       }
00413       freeQosArr(ret);
00414    }
00415 }
00416 
00417 XBFORCE_EXTERNC Dll_Export void xmlBlasterUnmanagedCEErase(struct XmlBlasterAccessUnparsed *xa, char * key,
00418      char * qos, XmlBlasterUnmanagedCEException *exception, uint32_t* pSize, XmlBlasterUnmanagedCEStringArr** ppStruct) {
00419    XmlBlasterException e;
00420    QosArr *ret = 0;
00421    initializeXmlBlasterException(&e);
00422    ret = xa->erase(xa, key, qos, &e);
00423    convert(&e, exception);
00424    if (freeIt) { xmlBlasterFree(key); key=0; }
00425    if (freeIt) { xmlBlasterFree(qos); qos=0; }
00426    if (*e.errorCode != 0) {
00427       if (ret) freeQosArr(ret);
00428       return;
00429    }
00430    if (ret) {
00431       size_t i;
00432       XmlBlasterUnmanagedCEStringArr* pCurStruct = 0;
00433       const uint32_t cArraySize = ret->len;
00434       *pSize = cArraySize;
00435       if (cArraySize == 0) {
00436          *ppStruct = 0;
00437       }
00438       else { 
00439          *ppStruct = (XmlBlasterUnmanagedCEStringArr*)malloc( cArraySize * sizeof( XmlBlasterUnmanagedCEStringArr ));
00440          pCurStruct = *ppStruct;
00441          for (i=0; i<ret->len; i++, pCurStruct++) {
00442             /*printf("dll: erase success, returned status is '%s'\n", ret->qosArr[i]);*/
00443             pCurStruct->str = strcpyAlloc(ret->qosArr[i]);
00444          }
00445       }
00446       freeQosArr(ret);
00447    }
00448 }
00449 
00450 XBFORCE_EXTERNC Dll_Export void xmlBlasterUnmanagedCEGet(struct XmlBlasterAccessUnparsed *xa,
00451         char * key, char *qos, XmlBlasterUnmanagedCEException *exception,
00452         uint32_t* pSize, MsgUnitUnmanagedCEget** ppStruct) {
00453    XmlBlasterException e;
00454    uint32_t i;
00455    MsgUnitArr *msgUnitArr = xa->get(xa, key, qos, &e);
00456    convert(&e, exception);
00457    if (freeIt) { xmlBlasterFree(key); key=0; }
00458    if (freeIt) { xmlBlasterFree(qos); qos=0; }
00459    if (*e.errorCode != 0) {
00460       return;
00461    }
00462    /*printf("dll: xmlBlasterUnmanagedCEGet building response\n");*/
00463    if (msgUnitArr != (MsgUnitArr *)0) {
00464       const uint32_t cArraySize = msgUnitArr->len;
00465       MsgUnitUnmanagedCEget* msgUnitUnmanagedP = 0;
00466       if (cArraySize == 0) {
00467          *ppStruct = 0;
00468          freeMsgUnitArr(msgUnitArr);
00469          return;
00470       } 
00471 
00472       *pSize = cArraySize;
00473       *ppStruct = (MsgUnitUnmanagedCEget*)malloc( cArraySize * sizeof( MsgUnitUnmanagedCEget ));
00474       msgUnitUnmanagedP = *ppStruct;
00475       /*printf("dll: xmlBlasterUnmanagedCEGet %ud\n", cArraySize);*/
00476       /* TODO: It should be possible to pass msgUnitArr->msgUnitArr* directly
00477          as it has the same memory layout as the IntPtr
00478       */
00479       /* NOTE:
00480          The sizeof(MsgUnitUnmanagedCEget) returns 20 bytes
00481          The same bytes are reported on the C# side (otherwise this approach fails)
00482       */
00483       for(i=0; i < cArraySize; i++, msgUnitUnmanagedP++) {
00484          MsgUnit *msgUnit = &msgUnitArr->msgUnitArr[i];
00485          char *cnt = (char *)malloc(msgUnit->contentLen*sizeof(char));
00486          /*printf("dll: xmlBlasterUnmanagedCEGet processing #%u\n", i);*/
00487          msgUnitUnmanagedP->contentLen = (int32_t)msgUnit->contentLen;
00488          if (cnt != 0) {
00489             size_t j;
00490             for (j=0; j<msgUnit->contentLen; j++) cnt[j] = (char)msgUnit->content[j];
00491          }
00492          msgUnitUnmanagedP->content = cnt;
00493          msgUnitUnmanagedP->key = strcpyAlloc(msgUnit->key);
00494          msgUnitUnmanagedP->qos = strcpyAlloc(msgUnit->qos);
00495          msgUnitUnmanagedP->responseQos = strcpyAlloc("<qos/>");
00496          /*printf("dll: xmlBlasterUnmanagedCEGet processing #%u key=%s qos=%s\n", i, msgUnitUnmanagedP->key, msgUnitUnmanagedP->qos);*/
00497       }
00498       freeMsgUnitArr(msgUnitArr);
00499    }
00500    /*printf("DONE in get\n");*/
00501 }
00502 
00503 XBFORCE_EXTERNC Dll_Export char *xmlBlasterUnmanagedCEPing(struct XmlBlasterAccessUnparsed *xa, char *qos, XmlBlasterUnmanagedCEException *exception) {
00504    XmlBlasterException e;
00505    char *ret = xa->ping(xa, qos, &e);
00506    convert(&e, exception);
00507    if (freeIt) { xmlBlasterFree(qos); qos=0; }
00508    return ret; 
00509 }
00510 
00511 XBFORCE_EXTERNC Dll_Export bool xmlBlasterUnmanagedCEIsConnected(struct XmlBlasterAccessUnparsed *xa) {
00512    return xa->isConnected(xa);
00513 }
00514 
00515 XBFORCE_EXTERNC Dll_Export const char *xmlBlasterUnmanagedCEUsage() {
00516    char *usage = (char *)malloc(XMLBLASTER_MAX_USAGE_LEN*sizeof(char));
00517    return xmlBlasterAccessUnparsedUsage(usage);
00518 }
00519 
00520 XBFORCE_EXTERNC Dll_Export const char *xmlBlasterUnmanagedCEVersion() {
00521    char *version = strcpyAlloc(getXmlBlasterVersion());
00522    return version;
00523 }
00524 
00525 #ifdef WINCE_EMEI
00526 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/apisp/html/sp_extapi_linegetgeneralinfo.asp */
00527 /* Tutorial: http://www.developer.com/ws/pc/print.php/10947_3503761_1 */
00528 #include <commctrl.h>
00529 #include "tapi.h"
00530 #include "extapi.h"
00531 
00532 #define TAPI_API_HIGH_VERSION   0x00020000
00533 #define EXT_API_LOW_VERSION     0x00010000
00534 #define EXT_API_HIGH_VERSION    0x00010000
00535    /*
00536    OS Versions: Windows CE 3.0 and later
00537    Header: extapi.h
00538    Library: cellcore.lib
00539    */
00540 
00541 #define DEVICE_ID_LENGTH            20
00542 #define APPLICATION_DATA            "@^!MyAppName!^@"
#define APPLICATION_DATA_LENGTH     15

static void GetTAPIErrorMsg(TCHAR *szMsg,int nSize, DWORD dwError)
{
        LPTSTR lpBuffer = 0;
        DWORD dwRet = 0;
        
        dwRet = ::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
                NULL,TAPIERROR_FORMATMESSAGE(dwError),MAKELANGID(LANG_NEUTRAL, LANG_NEUTRAL),
                (LPTSTR) &lpBuffer,0,NULL);
        memset(szMsg,0,nSize);
        if (lpBuffer && dwRet)
        {
                _tcscpy(szMsg,lpBuffer);
                LocalFree(lpBuffer);
        }
        else
        {
                _stprintf(szMsg,L"Unknown Error: 0x%X",dwError);
00543         }
00544 }
00545 #endif /* WINCE_EMEI */
00546 
00553 const char *getXmlBlasterEmei() {
00554 #ifdef WINCE_EMEI
00555    /*TCHAR imei[80]; // 40 should be OK */
00556    LPBYTE pLineGeneralInfoBytes = NULL;
00557    LINEGENERALINFO lineGeneralInfo;
00558    HLINEAPP hLineApp = 0;
00559    HLINE hLine = 0;
00560    DWORD dwNumDevs;
00561    DWORD dwAPIVersion = TAPI_API_HIGH_VERSION;
00562    DWORD dwExtVersion = 0;
00563    DWORD dwDeviceID;
00564    DWORD dwMediaMode = LINEMEDIAMODE_DATAMODEM; /* | LINEMEDIAMODE_INTERACTIVEVOICE; */
00565    LONG tapiresult; /* functions return 0 (SUCCESS) */
00566    LINEINITIALIZEEXPARAMS lineInitializeExParams;
00567 
00568    lineGeneralInfo.dwTotalSize = sizeof(lineGeneralInfo); 
00569 
00570    lineInitializeExParams.dwTotalSize = sizeof(lineInitializeExParams);
00571    lineInitializeExParams.dwOptions = LINEINITIALIZEEXOPTION_USEEVENT; /*The application desires to use the Event Handle event notification mechanism*/
00572    tapiresult = lineInitializeEx(&hLineApp, 0, 0, L"MyApp", &dwNumDevs, &dwAPIVersion, &lineInitializeExParams);
00573    if (tapiresult) {
00574       MessageBox(NULL, L"lineInitializeEx failed", _T("Unmanaged"), MB_OK);
00575       return 0;
00576    }
00577 
00578    /*MessageBox(NULL, L"lineInitializeEx OK", _T("Unmanaged"), MB_OK);*/
00579    for (dwDeviceID = 0; dwDeviceID < dwNumDevs; dwDeviceID++) {
00580       tapiresult = lineOpen(hLineApp, dwDeviceID, &hLine, dwAPIVersion, 0, 0,
00581                           LINECALLPRIVILEGE_OWNER, dwMediaMode, 0); /*returns 0 (SUCCESS)*/
00582       if (tapiresult) {
00583          MessageBox(NULL, L"lineOpen failed", _T("Unmanaged"), MB_OK);
00584          continue;
00585       }
00586 
00587       tapiresult = lineNegotiateExtVersion(hLineApp, dwDeviceID, dwAPIVersion,
00588                   EXT_API_LOW_VERSION, EXT_API_HIGH_VERSION, &dwExtVersion); /*returns 0 (SUCCESS)*/
00589       if (tapiresult) {
00590          MessageBox(NULL, L"lineNegotiateExtVersion failed", _T("Unmanaged"), MB_OK);
00591          continue;
00592       }
00593 
00594       tapiresult = lineGetGeneralInfo(hLine, &lineGeneralInfo); /*FAILs and gives error: -2147483595 (Invalid pointer)*/
00595       if (tapiresult != 0 && tapiresult != LINEERR_STRUCTURETOOSMALL) {
00596                    TCHAR szMsg[255];
00597                    GetTAPIErrorMsg(szMsg,sizeof(szMsg), tapiresult);
00598          MessageBox(NULL, szMsg, _T("Unmanaged"), MB_OK);
00599                    continue;
00600       }
00601 
00602       /*MessageBox(NULL, L"success!!!", _T("Unmanaged"), MB_OK);*/
00603 
00604       pLineGeneralInfoBytes = new BYTE[lineGeneralInfo.dwNeededSize];
00605       LPLINEGENERALINFO plviGeneralInfo;
00606       plviGeneralInfo = (LPLINEGENERALINFO)pLineGeneralInfoBytes;
00607         
00608       if(pLineGeneralInfoBytes != NULL) {
00609          plviGeneralInfo->dwTotalSize = lineGeneralInfo.dwNeededSize;
00610          if ((tapiresult = lineGetGeneralInfo(hLine, plviGeneralInfo)) != 0) {
00611                       TCHAR szMsg[255];
00612                       GetTAPIErrorMsg(szMsg,sizeof(szMsg), tapiresult);
00613             MessageBox(NULL, szMsg, _T("Unmanaged"), MB_OK);
00614          }
00615          else {
00616             LPTSTR tsManufacturer, tsModel, tsRevision, tsSerialNumber, tsSubscriberNumber;
00617                            TCHAR szUnavailable[] = L"Unavailable";
00618                            if(plviGeneralInfo->dwManufacturerSize) { 
00619                               tsManufacturer = (WCHAR*)(((BYTE*)plviGeneralInfo)+plviGeneralInfo->dwManufacturerOffset);
00620                            }
00621                            else {
00622                               tsManufacturer = szUnavailable;
00623                            }
00624                         
00625                            if(plviGeneralInfo->dwModelSize)     { 
00626                               tsModel = (WCHAR*)(((BYTE*)plviGeneralInfo)+plviGeneralInfo->dwModelOffset);
00627                            }
00628                            else {
00629                               tsModel = szUnavailable;
00630                            }
00631                         
00632                            if(plviGeneralInfo->dwRevisionSize)  {
00633                               tsRevision = (WCHAR*)(((BYTE*)plviGeneralInfo)+plviGeneralInfo->dwRevisionOffset);
00634                            }
00635                            else {
00636                               tsRevision = szUnavailable;
00637                            }
00638                         
00639                            if(plviGeneralInfo->dwSerialNumberSize) {
00640                               tsSerialNumber = (WCHAR*)(((BYTE*)plviGeneralInfo)+plviGeneralInfo->dwSerialNumberOffset);
00641                            }
00642                            else {
00643                               tsSerialNumber = szUnavailable;
00644                            }
00645                         
00646                            if(plviGeneralInfo->dwSubscriberNumberSize)
00647                            {
00648                               tsSubscriberNumber = (WCHAR*)(((BYTE*)plviGeneralInfo)+plviGeneralInfo->dwSubscriberNumberOffset);
00649                            }
00650                            else
00651                            {
00652                               tsSubscriberNumber = szUnavailable;
00653                            }
00654 
00655             /* AFXSTR.H*/
00656             /*typedef ATL::CStringT< TCHAR, StrTraitMFC< TCHAR > > CString;*/
00657             /*
00658             CString sInfo;
00659                            sInfo.Format(L"Manufacturer: %s\nModel: %s\nRevision: %s\nSerial No: %s\nSubscriber No: %s\n",
00660                                    tsManufacturer, 
00661                                    tsModel, 
00662                                    tsRevision, 
00663                                    tsSerialNumber, 
00664                                    tsSubscriberNumber);
00665             */
00666             char *imeiId = (char *)malloc(128);
00667             strcpy(imeiId, ( ( (char*)plviGeneralInfo) + lineGeneralInfo.dwSerialNumberOffset));
00668 
00669             /*MessageBox(NULL, (LPCWSTR)( ( (char*)plviGeneralInfo) + lineGeneralInfo.dwSerialNumberOffset),  _T("Unmanaged"), MB_OK);*/
00670             
00671             delete plviGeneralInfo;
00672             return imeiId;
00673          }
00674          delete plviGeneralInfo;
00675       }  
00676   } /* for */
00677   return 0;
00678 #else
00679    return strcpyAlloc("NotImplemented");
00680 #endif
00681 }
00682