LDicomNet::OnBeforeSendCommandSet

#include "ltwrappr.h"

virtual L_VOID LDicomNet::OnBeforeSendCommandSet(pCS)

Notifies a connection before the Command Set portion of a DIMSE LDicomNet:SendXxxResponse is transmitted.

Parameters

LDicomDS *pCS

A pointer to an LDicomDS containing the Command Set portion of a DIMSE SendXxxResponse message.

Returns

None.

Comments

This callback is fired for the following functions before the Command Set portion is sent:

This allows an SCP to add/remove DICOM elements to the Command Set cs prior to transmission.

This is useful for adding optional status elements for providing additional status information including:

Required DLLs and Libraries

Platforms

Win32, x64

See Also

Functions

Topics

Example

This example shows how to send/retrieve additional elements in a DICOM command set.
A C-STORE-REQ is to a SCP.
The SCP sends a C-STORE-RSP with Status of Refused: Out of Resources, and sets the optional element (0000,0902) ErrorComment
The SCU reads the optional command set element (0000,0902) ErrorComment

namespace LDicomNet_OnBeforeSendCommandSet_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); 
   } 
 
 
   // ******************************************************************************************* 
   // 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 OnReceiveCStoreResponse(L_UCHAR nPresentationID, L_UINT16 nMessageID, L_TCHAR *pszClass, L_TCHAR *pszInstance, L_UINT16 nStatus); 
 
      L_BOOL Wait(DWORD timeout = 5000); 
 
   private: 
      HANDLE m_waitEvent; 
   }; 
 
   // Continues dispatching messages until hEvent is signaled, our timeout 
   // Returns TRUE if hEvent is signaled 
   // 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::OnReceiveCStoreResponse(L_UCHAR nPresentationID, L_UINT16 nMessageID, L_TCHAR *pszClass, L_TCHAR *pszInstance, L_UINT16 nStatus) 
   { 
      if (pszClass == NULL) 
      { 
         pszClass = TEXT(""); 
      } 
 
      LogMessage(TEXT("CMyClient::OnReceiveCStoreResponse")); 
      LogMessage(TEXT("\t nPresentationID"), nPresentationID); 
      LogMessage(TEXT("\t nMessageID"), nMessageID); 
      LogMessage(TEXT("\t pszClass"), pszClass); 
      LogMessage(TEXT("\t pszInstance"), pszInstance); 
 
      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; 
 
      case COMMAND_STATUS_REFUSED_OUT_OF_RESOURCES: 
      { 
         LogMessage(TEXT("\t nStatus: COMMAND_STATUS_REFUSED_OUT_OF_RESOURCES")); 
         // Retrieve additional extra elements to the command set 
         LDicomDS *pCS = GetCommandSet(); 
         if (pCS != NULL) 
         { 
            pDICOMELEMENT pElement = pCS->FindFirstElement(NULL, TAG_ERROR_COMMENT, TRUE); 
            if (pElement != NULL) 
            { 
               L_TCHAR *pszErrorComment = pCS->GetStringValue(pElement, 0, 1); 
               LogMessage(TEXT("\t ErrorComment: "), pszErrorComment); 
            } 
         } 
      } 
      SetEvent(m_waitEvent); 
      break; 
      } 
 
      SetEvent(m_waitEvent); 
   } 
 
   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) 
      { 
      } 
      ~CMyServerConnection(void) 
      { 
      } 
 
      // Server 
      L_VOID OnReceiveAssociateRequest(LDicomAssociate *pPDU); 
      L_VOID OnReceiveCStoreRequest(L_UCHAR nPresentationID, L_UINT16 nMessageID, L_TCHAR *pszClass, L_TCHAR *pszInstance, L_UINT16 nPriority, L_TCHAR *pszMoveAE, L_UINT16 nMoveMessageID, LDicomDS *pDS); 
      L_VOID OnReceiveReleaseRequest(); 
      L_VOID OnBeforeSendCommandSet(LDicomDS *pCS); 
   }; 
 
#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::OnReceiveCStoreRequest(L_UCHAR nPresentationID, L_UINT16 nMessageID, L_TCHAR *pszClass, L_TCHAR *pszInstance, L_UINT16 nPriority, L_TCHAR *pszMoveAE, L_UINT16 nMoveMessageID, LDicomDS *pDS) 
   { 
      UNREFERENCED_PARAMETER(pDS); 
      UNREFERENCED_PARAMETER(pszMoveAE); 
 
      LogMessage(TEXT("\tCMyServerConnection::OnReceiveCStoreRequest")); 
      LogMessage(TEXT("\t nMoveMessageID"), nMoveMessageID); 
      LogMessage(TEXT("\t nPriority"), nPriority); 
 
      //... 
      //...Do the store here 
      //...nStatus = status of the store 
      LogMessage(TEXT("\t\t Do the store here")); 
 
      // Send C-Store-RSP 
      LogMessage(TEXT("\tCMyServerConnection::SendCStoreResponse")); 
      SendCStoreResponse(nPresentationID, nMessageID, pszClass, pszInstance, COMMAND_STATUS_SUCCESS); 
   } 
 
   L_VOID CMyServerConnection::OnBeforeSendCommandSet(LDicomDS *pCS) 
   { 
      // Add any extra elements to the command 
      // For this example, the store request will fail with a status of "Refused: Out of Resources" 
      // The reason is given in TAG_ERROR_COMMENT 
      if (pCS != NULL) 
      { 
         pDICOMELEMENT pElement = NULL; 
 
         pElement = pCS->FindFirstElement(NULL, TAG_STATUS, TRUE); 
         if (pElement != NULL) 
         { 
            L_UINT16 nStatus = COMMAND_STATUS_REFUSED_OUT_OF_RESOURCES; 
            pCS->SetShortValue(pElement, (L_INT16 *)&nStatus, 1); 
         } 
 
         pElement = pCS->InsertElement(NULL, FALSE, TAG_ERROR_COMMENT, VR_LO, FALSE, 0); 
         if (pElement != NULL) 
         { 
            L_TCHAR szErrorComment[] = TEXT("Out of disk space"); 
            pCS->SetStringValue(pElement, szErrorComment, 1); 
         } 
      } 
   } 
 
   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_OnBeforeSendCommandSetExample() 
   { 
      LogMessage(TEXT("\n\n *** OnBeforeSendCommandSetExample ***")); 
 
      L_TCHAR *pszServerAddress = TEXT("127.0.0.1"); 
      L_UINT uServerPort = 504; 
      L_INT nRet = DICOM_SUCCESS; 
 
      // Load the DICOM dataset that the client will store 
      LDicomDS ds; 
      // ds.LoadDS(MAKE_IMAGE_PATH(TEXT("IMAGE1.dcm")), DS_LOAD_CLOSE); 
      ds.LoadDS((TEXT("d:\\images\\image3.dcm")), DS_LOAD_CLOSE); 
 
      L_TCHAR *pszStorageClass = NULL; 
      pDICOMELEMENT pElement = ds.FindFirstElement(NULL, TAG_MEDIA_STORAGE_SOP_CLASS_UID, TRUE); 
      if (pElement != NULL) 
      { 
         pszStorageClass = ds.GetStringValue(pElement, 0, 1); 
      } 
 
      if (pszStorageClass == NULL || _tcslen(pszStorageClass) == 0) 
      { 
         pElement = ds.FindFirstElement(NULL, TAG_SOP_CLASS_UID, TRUE); 
         if (pElement != NULL) 
         { 
            pszStorageClass = ds.GetStringValue(pElement, 0, 1); 
         } 
      } 
 
      if (pszStorageClass == NULL || _tcslen(pszStorageClass) == 0) 
      { 
         pszStorageClass = UID_CT_IMAGE_STORAGE; // Default to CT Image Storage 
      } 
 
      // 
      // Get Image transfer syntax 
      // 
      L_TCHAR *pszTransferSyntax = NULL; 
      L_TCHAR *pszStorageInstance = NULL; 
      pElement = ds.FindFirstElement(NULL, TAG_TRANSFER_SYNTAX_UID, TRUE); 
      if (pElement != NULL) 
      { 
         pszTransferSyntax = ds.GetStringValue(pElement, 0, 1); 
      } 
 
      pElement = ds.FindFirstElement(NULL, TAG_SOP_INSTANCE_UID, TRUE); 
      if (pElement != NULL) 
      { 
         pszStorageInstance = ds.GetStringValue(pElement, 0, 1); 
      } 
 
      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("L20_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, pszStorageClass); 
         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(pszStorageClass); 
         L_UINT16 uUniqueID = 99; 
 
         LogMessage(TEXT("CMyClient::SendCStoreRequest")); 
 
         client.SendCStoreRequest(nPresentationID, uUniqueID, pszStorageClass, pszStorageInstance, COMMAND_PRIORITY_MEDIUM, TEXT("NONE"), 1, &ds); 
         WaitForProcessing(); 
      } 
 
      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 21.0.2021.7.2
Products | Support | Contact Us | Intellectual Property Notices
© 1991-2021 LEAD Technologies, Inc. All Rights Reserved.

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