Exemple #1
0
void MGPWorkitem::import(const MDomainObject& o)
{
  SOPInstanceUID(o.value("sopinsuid")); 
  SOPClassUID(o.value("sopclassuid")); 
  status(o.value("status")); 
  inputAvailabilityFlag(o.value("inputavailflag")); 
  priority(o.value("priority")); 
  procedureStepID(o.value("procstepid")); 
  startDateTime(o.value("startdattim")); 
  endDateTime(o.value("enddattim")); 
  resultStudyInstanceUID(o.value("resultstuinsuid")); 
  inputStudyInstanceUID(o.value("inputstuinsuid")); 
  multipleCopiesFlag(o.value("multcopyflag")); 
  description(o.value("description")); 
  patientID(o.value("patientid")); 
  patientName(o.value("patientname")); 
  patientBirthDate(o.value("birthdate")); 
  patientSex(o.value("sex")); 
  workItemCodeValue(o.value("workitemcodevalue")); 
  workItemCodeScheme(o.value("workitemcodescheme")); 
  workItemCodeMeaning(o.value("workitemcodemeaning")); 
  requestedProcAccessionNum(o.value("reqprocAccessionNum"));
  requestedProcID(o.value("reqprocID"));
  requestedProcDesc(o.value("reqprocDesc"));
  requestedProcCodevalue(o.value("reqprocCodevalue"));
  requestedProcCodemeaning(o.value("reqprocCodemeaning"));
  requestedProcCodescheme(o.value("reqprocCodescheme"));
  requestingPhysician(o.value("requestingPhys"));
  transactionUID(o.value("transactionUID"));
}
Exemple #2
0
void
MDBImageManager::setCriteria(const MPlacerOrder& order, MCriteriaVector& cv)
{
  MCriteria c;
  
  MString patientID(order.patientID());

  if (patientID.size())
  {
    c.attribute = "patid";
    c.oper      = TBL_EQUAL;
    c.value     = order.patientID();
    cv.push_back(c);
  }

#if 0
  MString issuer(order.issuerOfPatientID());

  if (issuer.size())
  {
    c.attribute = "issuer";
    c.oper      = TBL_EQUAL;
    c.value     = order.issuerOfPatientID();
    cv.push_back(c);
  }
#endif

  c.attribute = "plaordnum";
  c.oper      = TBL_EQUAL;
  c.value     = order.placerOrderNumber();
  cv.push_back(c);

}
Exemple #3
0
void
MDBImageManager::setCriteria(const MFillerOrder& order, MCriteriaVector& cv)
{
  MCriteria c;
  
  MString patientID(order.patientID());

  if (patientID.size())
  {
    c.attribute = "patid";
    c.oper      = TBL_EQUAL;
    c.value     = order.patientID();
    cv.push_back(c);
  }

#if 0
  MString issuer(order.issuerOfPatientID());

  if (issuer.size())
  {
    c.attribute = "issuer";
    c.oper      = TBL_EQUAL;
    c.value     = order.issuerOfPatientID();
    cv.push_back(c);
  }
#endif

  MString poNum(order.placerOrderNumber());

  if (poNum.size())
  {
    c.attribute = "plaordnum";
    c.oper      = TBL_EQUAL;
    c.value     = order.placerOrderNumber();
    cv.push_back(c);
  }

  c.attribute = "filordnum";
  c.oper      = TBL_EQUAL;
  c.value     = order.fillerOrderNumber();
  cv.push_back(c);

//  may include accession number also
/*
  MString accNum(order.accessionNumber());

  if (accNum.size())
  {
    c.attribute = "accnum";
    c.oper      = TBL_EQUAL;
    c.value     = order.accessionNumber();
    cv.push_back(c);
  }  */
}
//------------------------------------------------------------------------------
void ctkDICOMDatabasePrivate::insert( const ctkDICOMDataset& ctkDataset, const QString& filePath, bool storeFile, bool generateThumbnail)
{
  Q_Q(ctkDICOMDatabase);

  // Check to see if the file has already been loaded
  // TODO:
  // It could make sense to actually remove the dataset and re-add it. This needs the remove
  // method we still have to write.
  //

  QString sopInstanceUID ( ctkDataset.GetElementAsString(DCM_SOPInstanceUID) );

  QSqlQuery fileExists ( Database );
  fileExists.prepare("SELECT InsertTimestamp,Filename FROM Images WHERE SOPInstanceUID == :sopInstanceUID");
  fileExists.bindValue(":sopInstanceUID",sopInstanceUID);
  bool success = fileExists.exec();
  if (!success)
  {
    logger.error("SQLITE ERROR: " + fileExists.lastError().driverText());
    return;
  }
  qDebug() << "filename is: " << fileExists.value(1).toString();
  qDebug() << "modified date is: " << QFileInfo(fileExists.value(1).toString()).lastModified();
  qDebug() << "db mod date is: " << QDateTime::fromString(fileExists.value(0).toString(),Qt::ISODate);
  if ( fileExists.next() && QFileInfo(fileExists.value(1).toString()).lastModified() < QDateTime::fromString(fileExists.value(0).toString(),Qt::ISODate) )
  {
    logger.debug ( "File " + fileExists.value(1).toString() + " already added" );
    return;
  }

  //If the following fields can not be evaluated, cancel evaluation of the DICOM file
  QString patientsName(ctkDataset.GetElementAsString(DCM_PatientName) );
  QString studyInstanceUID(ctkDataset.GetElementAsString(DCM_StudyInstanceUID) );
  QString seriesInstanceUID(ctkDataset.GetElementAsString(DCM_SeriesInstanceUID) );
  QString patientID(ctkDataset.GetElementAsString(DCM_PatientID) );
  if ( patientsName.isEmpty() && !patientID.isEmpty() )
  { // Use patient id as name if name is empty - can happen on anonymized datasets
    // see: http://www.na-mic.org/Bug/view.php?id=1643
    patientsName = patientID;
  }
  if ( patientsName.isEmpty() || studyInstanceUID.isEmpty() || patientID.isEmpty() )
  {
    logger.error("Dataset is missing necessary information!");
    return;
  } 

  QString patientsBirthDate(ctkDataset.GetElementAsString(DCM_PatientBirthDate) );
  QString patientsBirthTime(ctkDataset.GetElementAsString(DCM_PatientBirthTime) );
  QString patientsSex(ctkDataset.GetElementAsString(DCM_PatientSex) );
  QString patientsAge(ctkDataset.GetElementAsString(DCM_PatientAge) );
  QString patientComments(ctkDataset.GetElementAsString(DCM_PatientComments) );
  QString studyID(ctkDataset.GetElementAsString(DCM_StudyID) );
  QString studyDate(ctkDataset.GetElementAsString(DCM_StudyDate) );
  QString studyTime(ctkDataset.GetElementAsString(DCM_StudyTime) );
  QString accessionNumber(ctkDataset.GetElementAsString(DCM_AccessionNumber) );
  QString modalitiesInStudy(ctkDataset.GetElementAsString(DCM_ModalitiesInStudy) );
  QString institutionName(ctkDataset.GetElementAsString(DCM_InstitutionName) );
  QString performingPhysiciansName(ctkDataset.GetElementAsString(DCM_PerformingPhysicianName) );
  QString referringPhysician(ctkDataset.GetElementAsString(DCM_ReferringPhysicianName) );
  QString studyDescription(ctkDataset.GetElementAsString(DCM_StudyDescription) );

  QString seriesDate(ctkDataset.GetElementAsString(DCM_SeriesDate) );
  QString seriesTime(ctkDataset.GetElementAsString(DCM_SeriesTime) );
  QString seriesDescription(ctkDataset.GetElementAsString(DCM_SeriesDescription) );
  QString bodyPartExamined(ctkDataset.GetElementAsString(DCM_BodyPartExamined) );
  QString frameOfReferenceUID(ctkDataset.GetElementAsString(DCM_FrameOfReferenceUID) );
  QString contrastAgent(ctkDataset.GetElementAsString(DCM_ContrastBolusAgent) );
  QString scanningSequence(ctkDataset.GetElementAsString(DCM_ScanningSequence) );

  long seriesNumber(ctkDataset.GetElementAsInteger(DCM_SeriesNumber) );
  long acquisitionNumber(ctkDataset.GetElementAsInteger(DCM_AcquisitionNumber) );
  long echoNumber(ctkDataset.GetElementAsInteger(DCM_EchoNumbers) );
  long temporalPosition(ctkDataset.GetElementAsInteger(DCM_TemporalPositionIdentifier) );

  // store the file if the database is not in memomry
  // TODO: if we are called from insert(file) we
  // have to do something else
  // 
  QString filename = filePath;
  if ( storeFile && !q->isInMemory() && !seriesInstanceUID.isEmpty() )
  {
    // QString studySeriesDirectory = studyInstanceUID + "/" + seriesInstanceUID;
    QString destinationDirectoryName = q->databaseDirectory() + "/dicom/";
    QDir destinationDir(destinationDirectoryName);
    filename = destinationDirectoryName +
        studyInstanceUID + "/" +
        seriesInstanceUID + "/" +
        sopInstanceUID;

    destinationDir.mkpath(studyInstanceUID + "/" +
                          seriesInstanceUID);

    if(filePath.isEmpty())
    {
      logger.debug ( "Saving file: " + filename );

      if ( !ctkDataset.SaveToFile( filename) )
      {
        logger.error ( "Error saving file: " + filename );
        return;
      }
    }
    else
    {
      // we're inserting an existing file

      QFile currentFile( filePath );
      currentFile.copy(filename);
      logger.debug( "Copy file from: " + filePath );
      logger.debug( "Copy file to  : " + filename );
    }
  }

  QSqlQuery checkPatientExistsQuery(Database);
  //The dbPatientID  is a unique number within the database, 
  //generated by the sqlite autoincrement
  //The patientID  is the (non-unique) DICOM patient id
  int dbPatientID = -1;

  if ( patientID != "" && patientsName != "" )
    {
    //Speed up: Check if patient is the same as in last file; 
    // very probable, as all images belonging to a study have the same patient
    if ( lastPatientID != patientID 
          || lastPatientsBirthDate != patientsBirthDate 
          || lastPatientsName != patientsName )
      {
      // Ok, something is different from last insert, let's insert him if he's not
      // already in the db.
      //

      // Check if patient is already present in the db
      // TODO: maybe add birthdate check for extra safety
      checkPatientExistsQuery.prepare ( "SELECT * FROM Patients WHERE PatientID = ? AND PatientsName = ?" );
      checkPatientExistsQuery.bindValue ( 0, patientID );
      checkPatientExistsQuery.bindValue ( 1, patientsName );
      loggedExec(checkPatientExistsQuery);

      if (checkPatientExistsQuery.next())
      {
        // we found him
        dbPatientID = checkPatientExistsQuery.value(checkPatientExistsQuery.record().indexOf("UID")).toInt();
      }
      else
        {
        // Insert it
        QSqlQuery insertPatientStatement ( Database );
        insertPatientStatement.prepare ( "INSERT INTO Patients ('UID', 'PatientsName', 'PatientID', 'PatientsBirthDate', 'PatientsBirthTime', 'PatientsSex', 'PatientsAge', 'PatientsComments' ) values ( NULL, ?, ?, ?, ?, ?, ?, ? )" );
        insertPatientStatement.bindValue ( 0, patientsName );
        insertPatientStatement.bindValue ( 1, patientID );
        insertPatientStatement.bindValue ( 2, patientsBirthDate );
        insertPatientStatement.bindValue ( 3, patientsBirthTime );
        insertPatientStatement.bindValue ( 4, patientsSex );
        // TODO: shift patient's age to study, 
        // since this is not a patient level attribute in images
        // insertPatientStatement.bindValue ( 5, patientsAge );
        insertPatientStatement.bindValue ( 6, patientComments );
        loggedExec(insertPatientStatement);
        dbPatientID = insertPatientStatement.lastInsertId().toInt();
        logger.debug ( "New patient inserted: " + QString().setNum ( dbPatientID ) );
        }
      /// keep this for the next image
      lastPatientUID = dbPatientID;
      lastPatientID = patientID;
      lastPatientsBirthDate = patientsBirthDate;
      lastPatientsName = patientsName;
      }

    // Patient is in now. Let's continue with the study

    if ( studyInstanceUID != "" && lastStudyInstanceUID != studyInstanceUID )
    {
      QSqlQuery checkStudyExistsQuery (Database);
      checkStudyExistsQuery.prepare ( "SELECT * FROM Studies WHERE StudyInstanceUID = ?" );
      checkStudyExistsQuery.bindValue ( 0, studyInstanceUID );
      checkStudyExistsQuery.exec();
      if(!checkStudyExistsQuery.next())
      {
        QSqlQuery insertStudyStatement ( Database );
        insertStudyStatement.prepare ( "INSERT INTO Studies ( 'StudyInstanceUID', 'PatientsUID', 'StudyID', 'StudyDate', 'StudyTime', 'AccessionNumber', 'ModalitiesInStudy', 'InstitutionName', 'ReferringPhysician', 'PerformingPhysiciansName', 'StudyDescription' ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )" );
        insertStudyStatement.bindValue ( 0, studyInstanceUID );
        insertStudyStatement.bindValue ( 1, dbPatientID );
        insertStudyStatement.bindValue ( 2, studyID );
        insertStudyStatement.bindValue ( 3, QDate::fromString ( studyDate, "yyyyMMdd" ) );
        insertStudyStatement.bindValue ( 4, studyTime );
        insertStudyStatement.bindValue ( 5, accessionNumber );
        insertStudyStatement.bindValue ( 6, modalitiesInStudy );
        insertStudyStatement.bindValue ( 7, institutionName );
        insertStudyStatement.bindValue ( 8, referringPhysician );
        insertStudyStatement.bindValue ( 9, performingPhysiciansName );
        insertStudyStatement.bindValue ( 10, studyDescription );
        if ( !insertStudyStatement.exec() )
        {
          logger.error ( "Error executing statament: " + insertStudyStatement.lastQuery() + " Error: " + insertStudyStatement.lastError().text() );
        }
        else
        {
          lastStudyInstanceUID = studyInstanceUID;
        }

      }
    }

    if ( seriesInstanceUID != "" && seriesInstanceUID != lastSeriesInstanceUID )
    {
      QSqlQuery checkSeriesExistsQuery (Database);
      checkSeriesExistsQuery.prepare ( "SELECT * FROM Series WHERE SeriesInstanceUID = ?" );
      checkSeriesExistsQuery.bindValue ( 0, seriesInstanceUID );
      logger.warn ( "Statement: " + checkSeriesExistsQuery.lastQuery() );
      loggedExec(checkSeriesExistsQuery);
      if(!checkSeriesExistsQuery.next())
      {
        QSqlQuery insertSeriesStatement ( Database );
        insertSeriesStatement.prepare ( "INSERT INTO Series ( 'SeriesInstanceUID', 'StudyInstanceUID', 'SeriesNumber', 'SeriesDate', 'SeriesTime', 'SeriesDescription', 'BodyPartExamined', 'FrameOfReferenceUID', 'AcquisitionNumber', 'ContrastAgent', 'ScanningSequence', 'EchoNumber', 'TemporalPosition' ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )" );
        insertSeriesStatement.bindValue ( 0, seriesInstanceUID );
        insertSeriesStatement.bindValue ( 1, studyInstanceUID );
        insertSeriesStatement.bindValue ( 2, static_cast<int>(seriesNumber) );
        insertSeriesStatement.bindValue ( 3, seriesDate );
        insertSeriesStatement.bindValue ( 4, QDate::fromString ( seriesTime, "yyyyMMdd" ) );
        insertSeriesStatement.bindValue ( 5, seriesDescription );
        insertSeriesStatement.bindValue ( 6, bodyPartExamined );
        insertSeriesStatement.bindValue ( 7, frameOfReferenceUID );
        insertSeriesStatement.bindValue ( 8, static_cast<int>(acquisitionNumber) );
        insertSeriesStatement.bindValue ( 9, contrastAgent );
        insertSeriesStatement.bindValue ( 10, scanningSequence );
        insertSeriesStatement.bindValue ( 11, static_cast<int>(echoNumber) );
        insertSeriesStatement.bindValue ( 12, static_cast<int>(temporalPosition) );
        if ( !insertSeriesStatement.exec() )
        {
          logger.error ( "Error executing statament: " 
            + insertSeriesStatement.lastQuery() 
            + " Error: " + insertSeriesStatement.lastError().text() );
          lastSeriesInstanceUID = "";
        }
        else
        {
          lastSeriesInstanceUID = seriesInstanceUID;
        }

      }
    }
    // TODO: what to do with imported files
    //
   if ( !filename.isEmpty() && !seriesInstanceUID.isEmpty() )
   {
     QSqlQuery checkImageExistsQuery (Database);
     checkImageExistsQuery.prepare ( "SELECT * FROM Images WHERE Filename = ?" );
     checkImageExistsQuery.bindValue ( 0, filename );
     checkImageExistsQuery.exec();
     if(!checkImageExistsQuery.next())
      {
        QSqlQuery insertImageStatement ( Database );
        insertImageStatement.prepare ( "INSERT INTO Images ( 'SOPInstanceUID', 'Filename', 'SeriesInstanceUID', 'InsertTimestamp' ) VALUES ( ?, ?, ?, ? )" );
        insertImageStatement.bindValue ( 0, sopInstanceUID );
        insertImageStatement.bindValue ( 1, filename );
        insertImageStatement.bindValue ( 2, seriesInstanceUID );
        insertImageStatement.bindValue ( 3, QDateTime::currentDateTime() );
        insertImageStatement.exec();
      }
    }

    if( generateThumbnail && thumbnailGenerator && !seriesInstanceUID.isEmpty() )
      {
      QString studySeriesDirectory = studyInstanceUID + "/" + seriesInstanceUID;
      //Create thumbnail here
      QString thumbnailPath = q->databaseDirectory() +
        "/thumbs/" + studyInstanceUID + "/" + seriesInstanceUID 
        + "/" + sopInstanceUID + ".png";
      QFileInfo thumbnailInfo(thumbnailPath);
      if( !(thumbnailInfo.exists() 
            && (thumbnailInfo.lastModified() > QFileInfo(filename).lastModified())))
        {
        QDir(q->databaseDirectory() + "/thumbs/").mkpath(studySeriesDirectory);
        DicomImage dcmImage(QDir::toNativeSeparators(filename).toAscii());
        thumbnailGenerator->generateThumbnail(&dcmImage, thumbnailPath);
        }
      }

    if (q->isInMemory())
      {
      emit q->databaseChanged();
      }
    }
}
Exemple #5
0
int main(int argc, char **argv)
{

  CONDITION cond;
  DUL_NETWORKKEY* network = NULL;
  DUL_ASSOCIATIONKEY* association = NULL;
  DUL_ASSOCIATESERVICEPARAMETERS params;
  char
    *calledAPTitle = "CFIND_SCP",
    *callingAPTitle = "CFIND_SCU";

  char localHost[40] = "";

  int port;
  char *node;

  CTNBOOLEAN
    verbose = FALSE,
    abortFlag = FALSE,
    paramsFlag = FALSE;
  char *fileName = NULL;
  DUL_SC_ROLE
    role = DUL_SC_ROLE_DEFAULT;

  char* sopClass = DICOM_SOPSTUDYQUERY_FIND;
  char* outputPath = "";

  while (--argc > 0 && (*++argv)[0] == '-') {
    switch (*(argv[0] + 1)) {
    case 'a':
      argc--;
      argv++;
      if (argc <= 0)
	usageerror();
      callingAPTitle = *argv;
      break;
    case 'c':
      argc--;
      argv++;
      if (argc <= 0)
	usageerror();
      calledAPTitle = *argv;
      break;
    case 'o':
      argc--;
      argv++;
      if (argc <= 0)
	usageerror();
      outputPath = *argv;
      break;
    case 'v':
      verbose = TRUE;
      break;
    default:
      break;
    }
  }

  if (argc < 5)
    usageerror();

  ::THR_Init();
  ::DUL_Debug(verbose);
  ::SRV_Debug(verbose);

  node = *argv;
  if (sscanf(*++argv, "%d", &port) != 1)
    usageerror();

  if( gethostname(localHost, sizeof(localHost)) != 0) {
	  // gethostname is failing under Win32
	  //fprintf(stderr, "gethostname() failed.\n");
  }

  cond = DUL_InitializeNetwork(DUL_NETWORK_TCP, DUL_AEREQUESTOR,
				 NULL, 10, DUL_ORDERBIGENDIAN, &network);
  if (cond != DUL_NORMAL)
    myExit(&association);

  ::DUL_DefaultServiceParameters(&params);
  ::sprintf(params.calledPresentationAddress, "%s:%s", node, *argv);
  ::strcpy(params.callingPresentationAddress, localHost);
  ::strcpy(params.calledAPTitle, calledAPTitle);
  ::strcpy(params.callingAPTitle, callingAPTitle);
  cond = ::SRV_RequestServiceClass(sopClass, role, &params);
  if (cond != SRV_NORMAL) {
    ::COND_DumpConditions();
    ::THR_Shutdown();
    ::exit(1);
  }

  cond = ::DUL_RequestAssociation(&network, &params, &association);
  if (cond != DUL_NORMAL) {
    if (cond == DUL_ASSOCIATIONREJECTED) {
      ::fprintf(stderr, "Association Rejected\n");
      ::fprintf(stderr, " Result: %2x Source %2x Reason %2x\n",
		params.result, params.resultSource,
		params.diagnostic);
    }
    myExit(&association);
  }
  if (verbose || paramsFlag) {
    (void) ::printf("Association accepted, parameters:\n");
    ::DUL_DumpParams(&params);
  }

  MString patientID(*++argv);
  MDICOMWrapper qStudy(*++argv);
  qStudy.setString(0x00100020, patientID);
  MDICOMWrapper qSeries(*++argv);
  MDICOMWrapper qSOPInstance(*++argv);

  DCM_OBJECT* queryObj = qStudy.getNativeObject();

  MLQuery qHandlerStudy(outputPath);
  MLQuery qHandlerSeries(outputPath);
  MLQuery qHandlerInstance(outputPath);

  MDICOMReactor reactor;

  reactor.registerHandler(&qHandlerStudy, sopClass);
  qHandlerStudy.sendCFindRequest(&association, &params,
			    sopClass, &queryObj);
  reactor.processRequests(&association, &params, 1);

  WRAPPERVector studyVector = qHandlerStudy.wrapperVector();


  WRAPPERVector::iterator studyIterator = studyVector.begin();
  for (; studyIterator != studyVector.end(); studyIterator++) {
    MDICOMWrapper* w = *studyIterator;

    DCM_OBJECT* obj = w->getNativeObject();
    ::DCM_FormatElements(&obj, 1, "");
    reactor.registerHandler(&qHandlerSeries, sopClass);

    MString studyUID = w->getString(0x0020000D);
    qSeries.setString(0x0020000D, studyUID);

    DCM_OBJECT* seriesQueryObj = qSeries.getNativeObject();
    qHandlerSeries.sendCFindRequest(&association, &params,
				    sopClass, &seriesQueryObj);

    qHandlerSeries.clearVector();
    reactor.processRequests(&association, &params, 1);

    WRAPPERVector seriesVector = qHandlerSeries.wrapperVector();

    WRAPPERVector::iterator seriesIterator = seriesVector.begin();
    for (; seriesIterator != seriesVector.end(); seriesIterator++) {
      MDICOMWrapper* w2 = *seriesIterator;
      DCM_OBJECT* objSeries = w2->getNativeObject();
      ::DCM_FormatElements(&objSeries, 1, "  ");

      reactor.registerHandler(&qHandlerInstance, sopClass);
      MString seriesUID = w2->getString(0x0020000E);
      qSOPInstance.setString(0x0020000D, studyUID);
      qSOPInstance.setString(0x0020000E, seriesUID);
      DCM_OBJECT* instanceQueryObj = qSOPInstance.getNativeObject();
      qHandlerInstance.sendCFindRequest(&association, &params,
					sopClass, &instanceQueryObj);
      qHandlerInstance.clearVector();
      reactor.processRequests(&association, &params, 1);

      WRAPPERVector instanceVector = qHandlerInstance.wrapperVector();

      WRAPPERVector::iterator instanceIterator = instanceVector.begin();
      for (; instanceIterator != instanceVector.end(); instanceIterator++) {
	MDICOMWrapper* w3 = *instanceIterator;
	DCM_OBJECT* objInstance = w3->getNativeObject();
	::DCM_FormatElements(&objInstance, 1, "    ");
      }
    }
  }


  cond = ::DUL_ReleaseAssociation(&association);
  if (cond != DUL_RELEASECONFIRMED) {
    (void) ::fprintf(stderr, "%x\n", cond);
    ::COND_DumpConditions();
  }
  (void) ::DUL_ClearServiceParameters(&params);

  (void) ::DUL_DropNetwork(&network);
  ::THR_Shutdown();
  return 0;
}