LDicomNet::SendCFindRequest

Summary

Sends a C-FIND-REQ message to a peer member of a connection. This function is available in the PACS Imaging Toolkit.

Syntax

#include "ltdic.h"

L_INT LDicomNet::SendCFindRequest(nPresentationID, nMessageID, pszClass, nPriority, pDS)

Parameters

L_UCHAR nPresentationID

Presentation ID. The presentation ID provides information about both the class type of the data and the transfer syntax to use when transferring the data.

L_UINT16 nMessageID

Message ID. Each message sent by a member of a connection should have a unique ID. Since a member of a connection may send several messages, this ID allows that member to identify when a specific request has been completed.

L_TCHAR * pszClass

Class affected by the request. This will be an SOP Class or an SOP MetaClass.

L_UINT16 nPriority

The priority level of the message. The Service Class Provider may or may not support priority. Therefore, setting this parameter may or may not have any effect. Possible values are:

Value Meaning
COMMAND_PRIORITY_LOW [0x0002] Low priority message.
COMMAND_PRIORITY_MEDIUM [0x0000] Medium priority message.
COMMAND_PRIORITY_HIGH [0x0001] High priority message.

LDicomDS * pDS

Pointer to the data set to be found.

Returns

Value Meaning
0 SUCCESS
>0 An error occurred. Refer to Return Codes.

Comments

Calling this function generates a call to LDicomNet::OnReceiveCFindRequest on the SCP. The SCP should respond by calling LDicomNet::SendCFindResponse which will generate a call to LDicomNet::OnReceiveCFindResponse.

You must create a data set and insert elements corresponding to the data you wish to find. A pointer to this data set is then passed as a parameter to this function.

Required DLLs and Libraries

Platforms

Win32, x64

See Also

Functions

Topics

Example

This is a basic, but complete example that shows a DICOM client sending a C-Find-REQ to a server, and the server sending three C-Find-RSP to the client.

namespace LDicomNet_SendCFindRequest_Namespace 
{ 
   // Logs a message 
   // This implementation logs to the console, and the debug window 
   L_VOID LogMessage(TCHAR *szMsg) 
   { 
      wprintf(TEXT("\n")); 
      wprintf(szMsg); 
 
      OutputDebugStringW(TEXT("\n")); 
      OutputDebugStringW(szMsg); 
   } 
 
   L_VOID LogMessage(TCHAR *s, L_INT n) 
   { 
      TCHAR szLog[200] = {0}; 
      wsprintf(szLog, TEXT("%s [%d]"), s, n); 
      LogMessage(szLog); 
   } 
 
   L_VOID LogMessage(TCHAR *s, TCHAR *s2) 
   { 
      TCHAR szLog[200] = {0}; 
      wsprintf(szLog, TEXT("%s [%s]"), s, s2); 
      LogMessage(szLog); 
   } 
 
   L_VOID InsertKeyElementAndSetValue(LDicomDS& responseDS, LDicomDS& requestDS, L_UINT32 uTag, L_UINT16 uVR, L_TCHAR *pszValue)  
   { 
      pDICOMELEMENT pElement = requestDS.FindFirstElement(NULL, uTag, TRUE); 
      pDICOMELEMENT pNew = NULL; 
      if (pElement) 
      { 
         pNew = responseDS.InsertElement(NULL, FALSE, uTag, uVR, FALSE, 0); 
      } 
 
      if (pNew && pszValue) 
      { 
         responseDS.SetConvertValue(pNew, pszValue, 1); 
      } 
   } 
 
   L_VOID SetElement(LDicomDS* pDataSet, L_UINT32 uTag, L_UINT16 uVR, L_TCHAR* pszValue)  
   { 
      if (pDataSet == NULL) 
         return; 
 
      pDICOMELEMENT pElement = pDataSet->FindFirstElement(NULL, uTag, TRUE); 
      if (pElement == NULL) 
      { 
         pElement = pDataSet->InsertElement(NULL, FALSE, uTag, uVR, FALSE, 0); 
      } 
      if (pElement && pszValue) 
      { 
         pDataSet->SetConvertValue(pElement, pszValue, 1); 
      } 
   } 
 
   L_VOID PrepareCFindResponseDataset(LDicomDS& responseDS, LDicomDS& requestDS, L_TCHAR *pszStudyInstanceUid) 
   { 
      pDICOMELEMENT pElement = NULL; 
 
      responseDS.InitDS(CLASS_UNKNOWN,DS_METAHEADER_ABSENT | DS_LITTLE_ENDIAN | DS_EXPLICIT_VR); 
 
      // The Query/Retrieve Level 
      SetElement(&responseDS, TAG_QUERY_RETRIEVE_LEVEL, VR_CS, TEXT("STUDY")); 
 
      // The Unique Keys 
      pElement = responseDS.InsertElement(NULL, FALSE, TAG_STUDY_INSTANCE_UID, VR_UI, FALSE, 0); 
      responseDS.SetStringValue(pElement, pszStudyInstanceUid, 1); 
 
      // Required Keys: 
      InsertKeyElementAndSetValue(responseDS, requestDS, TAG_STUDY_DATE, VR_DA, TEXT("01/02/1999")); 
      InsertKeyElementAndSetValue(responseDS, requestDS, TAG_STUDY_TIME, VR_TM, TEXT("05:43:00")); 
      InsertKeyElementAndSetValue(responseDS, requestDS, TAG_ACCESSION_NUMBER, VR_SH, TEXT("001")); 
      InsertKeyElementAndSetValue(responseDS, requestDS, TAG_STUDY_ID, VR_SH, TEXT("111")); 
 
      InsertKeyElementAndSetValue(responseDS, requestDS, TAG_PATIENT_NAME, VR_PN, TEXT("SMITH^JOE")); 
      InsertKeyElementAndSetValue(responseDS, requestDS, TAG_PATIENT_ID, VR_LO, TEXT("1234")); 
 
      // Optional Keys: 
      InsertKeyElementAndSetValue(responseDS, requestDS, TAG_STUDY_DESCRIPTION, VR_LO, NULL); 
      InsertKeyElementAndSetValue(responseDS, requestDS, TAG_NUMBER_OF_STUDY_RELATED_SERIES, VR_IS, NULL); 
      InsertKeyElementAndSetValue(responseDS, requestDS, TAG_NUMBER_OF_STUDY_RELATED_INSTANCES, VR_IS, NULL); 
   } 
 
 
   // ******************************************************************************************* 
   // Client Class  
   // 
   // Class that is used to connect to the server  
   // ******************************************************************************************* 
   class CMyClient : public LDicomNet 
   { 
   public: 
      CMyClient(L_INT32 nMode): LDicomNet(NULL, nMode) 
      { 
         m_waitEvent = CreateEvent( NULL, TRUE, TRUE, TEXT("ClientEvent")); 
         ResetEvent(m_waitEvent); 
      } 
 
      ~CMyClient(void) 
      { 
         CloseHandle(m_waitEvent); 
      } 
 
      // Client 
      L_VOID OnConnect                    (L_INT nError); 
      L_VOID OnReceiveAssociateAccept     (LDicomAssociate *pPDU); 
      L_VOID OnReceiveReleaseResponse     (); 
      L_VOID OnReceiveCFindResponse       (L_UCHAR nPresentationID, L_UINT16 nMessageID, L_TCHAR *pszClass, L_UINT16 nStatus, LDicomDS *pDS); 
 
      L_BOOL Wait(DWORD timeout = 5000); 
 
   private: 
      HANDLE m_waitEvent; 
   }; 
 
   // Continues dispatching messages until hEvent is signalled, our timeout 
   // Returns TRUE if hEvent is signalled 
   // Returns FALSE if timeout 
   L_BOOL MessageLoop ( 
      HANDLE hEvent, // handles that need to be waited on 
      DWORD timeout  // timeout in milliseconds 
      ) 
   { 
      DWORD dwStart = GetTickCount(); 
      MSG msg = {0}; 
 
      volatile L_BOOL bRunForever = TRUE; 
      while (bRunForever) 
      { 
         if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))  
         { 
            TranslateMessage(&msg); 
            DispatchMessage(&msg); 
         } 
 
         if (WaitForSingleObject(hEvent, 0) == WAIT_OBJECT_0) 
         { 
            ResetEvent(hEvent); 
            return TRUE; 
         } 
 
         DWORD dwCurrent = GetTickCount(); 
         if ((dwCurrent - dwStart) > timeout) 
         { 
            return FALSE; 
         } 
      } 
      return TRUE; 
   } 
 
   L_VOID CMyClient::OnConnect(L_INT nError) 
   { 
      L_TCHAR szMsg[200] = {0}; 
 
      wsprintf(szMsg, TEXT("CMyClient::OnConnect: nError[%d]"), nError);  
      LogMessage(szMsg); 
   } 
 
   L_VOID CMyClient::OnReceiveAssociateAccept  (LDicomAssociate *pPDU) 
   { 
      UNREFERENCED_PARAMETER(pPDU); 
      LogMessage(TEXT("CMyClient::OnReceiveAssociateAccept")); 
      SetEvent(m_waitEvent); 
   } 
    
   L_VOID CMyClient::OnReceiveCFindResponse(L_UCHAR nPresentationID, L_UINT16 nMessageID, L_TCHAR *pszClass, L_UINT16 nStatus, LDicomDS *pDS) 
   { 
      UNREFERENCED_PARAMETER(pDS); 
 
      if (pszClass == NULL) 
      { 
         pszClass = TEXT(""); 
      } 
 
      LogMessage(TEXT("CMyClient::OnReceiveCFindResponse")); 
      LogMessage(TEXT("\t nPresentationID"), nPresentationID); 
      LogMessage(TEXT("\t nMessageID"), nMessageID); 
      LogMessage(TEXT("\t pszClass"), pszClass); 
       
      switch(nStatus) 
         { 
      case COMMAND_STATUS_WARNING: 
         LogMessage(TEXT("\t nStatus: COMMAND_STATUS_WARNING")); 
         break; 
 
      case COMMAND_STATUS_PENDING_WARNING: 
         LogMessage(TEXT("\t nStatus: COMMAND_STATUS_PENDING_WARNING")); 
         break; 
 
      case COMMAND_STATUS_PENDING: 
         LogMessage(TEXT("\t nStatus: COMMAND_STATUS_PENDING")); 
         break; 
 
      case COMMAND_STATUS_SUCCESS: 
         LogMessage(TEXT("\t nStatus: COMMAND_STATUS_SUCCESS")); 
         SetEvent(m_waitEvent); 
         break; 
      } 
   } 
 
   L_VOID CMyClient::OnReceiveReleaseResponse() 
   { 
      LogMessage(TEXT("CMyClient::OnReceiveReleaseResponse")); 
      SetEvent(m_waitEvent); 
   } 
 
   L_BOOL CMyClient::Wait(DWORD timeout) 
   { 
      L_BOOL bRet = MessageLoop(m_waitEvent,  timeout);   
      return bRet; 
   } 
 
   // ******************************************************************************************* 
   // Server Connection Class  
   // 
   // When a client connects, CMyServer creates a new instance of the CMyServerConnection class  
   // and accepts the connection.   
   // ******************************************************************************************* 
   class CMyServerConnection : public LDicomNet 
   { 
   public: 
      CMyServerConnection(L_INT32 nMode): LDicomNet(NULL, nMode) 
      { 
         m_waitEvent = CreateEvent( NULL, TRUE, TRUE, TEXT("ServerConnectionEvent")); 
         ResetEvent(m_waitEvent); 
      } 
      ~CMyServerConnection(void) 
      { 
         CloseHandle(m_waitEvent); 
      } 
 
   private: 
      HANDLE m_waitEvent; 
 
      // Server 
      L_VOID OnReceiveAssociateRequest(LDicomAssociate *pPDU); 
      L_VOID OnReceiveCFindRequest(L_UCHAR nPresentationID, L_UINT16 nMessageID, L_TCHAR *pszClass, L_UINT16 nPriority, LDicomDS *pDS); 
      L_VOID OnReceiveReleaseRequest(); 
   }; 
 
   #define SIZEINWORD(p) sizeof(p)/sizeof(L_TCHAR) 
   L_VOID CMyServerConnection::OnReceiveAssociateRequest(LDicomAssociate *pPDU) 
   { 
      LogMessage(TEXT("\tCMyServerConnection::OnReceiveAssociateRequest")); 
 
      
         LDicomAssociate DicomAssociate(FALSE); 
 
         L_TCHAR clientAE[20] = {0}; 
         pPDU->GetCalling(clientAE, 20); 
 
         //Copy presentation objects from received 
         //Reply that we only support the first Transfer Syntax from the received hPDU 
         L_TCHAR szTransfer[PDU_MAX_UID_SIZE+1] = {0}; 
         L_TCHAR szAbstract[PDU_MAX_UID_SIZE+1] = {0}; 
         L_INT iPresentationCount = pPDU->GetPresentationCount(); 
         for (L_UCHAR i = 0; i<iPresentationCount; i++) 
         { 
            L_UCHAR nId = pPDU->GetPresentation(i); 
            pPDU->GetTransfer(nId, 0, szTransfer, PDU_MAX_UID_SIZE+1); 
            L_UCHAR nResult = PDU_ACCEPT_RESULT_SUCCESS; 
            pPDU->GetAbstract(nId, szAbstract, PDU_MAX_UID_SIZE+1); 
            DicomAssociate.AddPresentation( nId, nResult, szAbstract); 
            DicomAssociate.AddTransfer( nId, szTransfer); 
         } 
 
         LogMessage(TEXT("\tCMyServerConnection::SendAssociateAccept")); 
         SendAssociateAccept(&DicomAssociate); 
   } 
 
   L_VOID CMyServerConnection::OnReceiveCFindRequest(L_UCHAR nPresentationID, L_UINT16 nMessageID, L_TCHAR *pszClass, L_UINT16 nPriority, LDicomDS *pDS) 
   { 
      UNREFERENCED_PARAMETER(pDS); 
      LogMessage(TEXT("\tCMyServerConnection::OnReceiveCFindRequest")); 
 
      L_UINT  lPeerPort = 0; 
      L_TCHAR  szPeerAddress[200] = {0}; 
 
      GetPeerInfo(szPeerAddress,100, &lPeerPort); 
 
      LogMessage(TEXT("\t\t Peer"), szPeerAddress); 
      LogMessage(TEXT("\t\t nPresentationID"), nPresentationID); 
      LogMessage(TEXT("\t\t nMessageID"), nMessageID); 
      LogMessage(TEXT("\t\t pszClass"), pszClass); 
      LogMessage(TEXT("\t\t nPriority"), nPriority); 
 
      //For this example, assume the following two files match the find criteria 
 
      // Prepare first pending C-Find-RSP 
      LDicomDS ds1; 
      PrepareCFindResponseDataset(ds1, *pDS, TEXT("1.1.1.1")); 
      LogMessage(TEXT("\tCMyServerConnection::SendCFindResponse (0) -- PENDING")); 
      SendCFindResponse (nPresentationID, nMessageID, pszClass, COMMAND_STATUS_PENDING, &ds1); 
 
      // Prepare second pending C-Find-RSP 
      LDicomDS ds2; 
      PrepareCFindResponseDataset(ds2, *pDS, TEXT("1.1.1.2")); 
      LogMessage(TEXT("\tCMyServerConnection::SendCFindResponse (1) -- PENDING")); 
      SendCFindResponse (nPresentationID, nMessageID, pszClass, COMMAND_STATUS_PENDING, &ds2); 
 
      // Send Final C-Find-RSP 
      LogMessage(TEXT("\tCMyServerConnection::SendCFindResponse (2) -- SUCCESS")); 
      SendCFindResponse(nPresentationID, nMessageID, pszClass, COMMAND_STATUS_SUCCESS, NULL); 
   } 
 
   L_VOID CMyServerConnection::OnReceiveReleaseRequest() 
   { 
      LogMessage(TEXT("\tCMyServerConnection::OnReceiveReleaseRequest")); 
      LogMessage(TEXT("\tCMyServerConnection::SendReleaseResponse")); 
      SendReleaseResponse(); 
   } 
 
   // ******************************************************************************************* 
   // Server Class  
   // 
   // Listens for connections 
   // When a client connects, this class creates a CMyServerConnection and accepts the connection 
   // ******************************************************************************************* 
   class CMyServer : public LDicomNet 
   { 
   public: 
      CMyServer(L_INT32 nMode): LDicomNet(NULL, nMode) 
      { 
         m_pServerConnection = NULL; 
      } 
 
      ~CMyServer(void) 
      { 
         if (m_pServerConnection != NULL) 
         { 
            delete m_pServerConnection; 
         } 
      } 
 
      L_VOID OnAccept       (L_INT nError); 
      L_VOID OnClose        (L_INT nError, LDicomNet *pServerConnection); 
 
      CMyServerConnection *m_pServerConnection; 
   }; 
 
   L_VOID CMyServer::OnAccept(L_INT nError) 
   { 
      LogMessage(TEXT("\tCMyServer::OnAccept")); 
      if (nError != DICOM_SUCCESS) 
      { 
         return; 
      } 
 
      if (m_pServerConnection != NULL) 
      { 
         delete m_pServerConnection; 
         m_pServerConnection = NULL; 
      } 
 
      m_pServerConnection = new CMyServerConnection(DICOM_SECURE_NONE); 
      if (m_pServerConnection == NULL) 
      { 
         return; 
      } 
 
      // m_pServerConnection->EnableOptimizedSend(TRUE); 
      nError = LDicomNet::Accept(m_pServerConnection); 
      if (nError != DICOM_SUCCESS) 
      { 
         delete m_pServerConnection; 
         return; 
      } 
   } 
 
   L_VOID CMyServer::OnClose(L_INT nError, LDicomNet *pServerConnection) 
   { 
      UNREFERENCED_PARAMETER(nError); 
      LogMessage(TEXT("\tCMyServer::OnClose")); 
      if (m_pServerConnection == pServerConnection) 
      { 
         m_pServerConnection = NULL; 
      } 
      delete (CMyServerConnection *)pServerConnection; 
   } 
 
   // ******************************************************************************************* 
   // Sample starts here  
   // ******************************************************************************************* 
   #define WaitForProcessing() \ 
   { \ 
      if (!client.Wait()) \ 
      { \ 
         LogMessage(TEXT("Timeout: client.Connect")); \ 
         nRet = DICOM_ERROR_NET_TIME_OUT; \ 
         goto Cleanup; \ 
      } \ 
   }  
 
   L_INT LDicomNet_SendCFindRequestExample() 
   { 
      LogMessage(TEXT("\n\n *** SendCFindRequestExample ***")); 
 
      L_TCHAR *pszServerAddress = TEXT("127.0.0.1"); 
      L_UINT uServerPort = 105; 
      L_INT nRet = DICOM_SUCCESS; 
 
      LDicomNet::StartUp(); 
 
      CMyClient client(DICOM_SECURE_NONE); 
      CMyServer server(DICOM_SECURE_NONE); 
      
      LogMessage(TEXT("\tCMyServer::Listen")); 
      nRet = server.Listen(pszServerAddress, uServerPort, 5); 
 
      LogMessage(TEXT("CMyClient::Connect")); 
      client.Connect(NULL, 0, pszServerAddress, uServerPort); 
      if (!client.Wait(2000)) 
      { 
         if (!client.IsConnected()) 
         { 
            LogMessage(TEXT("Timeout: client.Connect"));  
            nRet = DICOM_ERROR_NET_TIME_OUT; 
            goto Cleanup; 
         } 
      } 
 
      if (nRet == DICOM_SUCCESS) 
      { 
         //create the Associate Class as Request 
         LDicomAssociate dicomAssociateRequest(TRUE); 
 
         dicomAssociateRequest.SetCalled(TEXT("L19_PACS_SCP32")); 
         dicomAssociateRequest.SetCalling(TEXT("LEAD_CLIENT")); 
 
         dicomAssociateRequest.SetImplementClass(TRUE, TEXT("1.2.840.114257.1")); 
         dicomAssociateRequest.SetImplementVersion(TRUE, TEXT("1")); 
         dicomAssociateRequest.SetMaxLength(TRUE, 0x100000); 
 
         dicomAssociateRequest.AddPresentation(1, 0, UID_VERIFICATION_CLASS); 
         dicomAssociateRequest.AddTransfer(1, UID_IMPLICIT_VR_LITTLE_ENDIAN); 
         dicomAssociateRequest.AddPresentation(3, 0, UID_STUDY_ROOT_QUERY_FIND); 
         dicomAssociateRequest.AddTransfer(3, UID_IMPLICIT_VR_LITTLE_ENDIAN); 
 
         // Send A-Associate-RQ message 
         LogMessage(TEXT("CMyClient::SendAssociateRequest")); 
         nRet = client.SendAssociateRequest(&dicomAssociateRequest); 
         if (!client.Wait(5000)) 
         { 
            LogMessage(TEXT("Timeout: client.Connect"));  
            nRet = DICOM_ERROR_NET_TIME_OUT; 
            goto Cleanup; 
         } 
      } 
 
      if (nRet == DICOM_SUCCESS) 
      { 
         L_UCHAR nPresentationID = client.GetAssociate()->FindAbstract(UID_STUDY_ROOT_QUERY_FIND); 
         L_UINT16 uUniqueID = 99; 
 
         // Create the find dataset for a Study level, study-root Query 
         LDicomDS ds; 
         ds.InitDS(CLASS_STUDY_ROOT_QUERY_STUDY, DS_ADD_MANDATORY_ELEMENTS_ONLY | DS_ADD_MANDATORY_MODULES_ONLY); 
         pDICOMELEMENT pElement = ds.FindFirstElement(NULL, TAG_QUERY_RETRIEVE_LEVEL, TRUE); 
         assert(pElement != NULL); 
         ds.SetStringValue(pElement, TEXT("STUDY"),1, DICOM_CHARACTER_SET_DEFAULT); 
 
         LogMessage(TEXT("CMyClient::SendCFindRequest")); 
         L_UINT uRet = client.SendCFindRequest(nPresentationID, uUniqueID, UID_STUDY_ROOT_QUERY_FIND, COMMAND_PRIORITY_MEDIUM, &ds); 
         UNREFERENCED_PARAMETER(uRet); 
         WaitForProcessing(); 
         // client.Wait(10000); 
      } 
 
      LogMessage(TEXT("CMyClient::SendReleaseRequest")); 
      client.SendReleaseRequest(); 
      WaitForProcessing(); 
Cleanup: 
      LogMessage(TEXT("CMyClient::Close")); 
      client.Close(); 
      client.Wait(1000); 
 
      LogMessage(TEXT("\tCMyServer::Close")); 
      server.Close(); 
 
      LDicomNet::ShutDown(); 
 
      return nRet; 
   } 
 
} 

Help Version 23.0.2024.7.1
Products | Support | Contact Us | Intellectual Property Notices
© 1991-2024 LEAD Technologies, Inc. All Rights Reserved.

LEADTOOLS DICOM C++ Class Library Help
Products | Support | Contact Us | Intellectual Property Notices
© 1991-2023 LEAD Technologies, Inc. All Rights Reserved.