// LMyDicomNet.cpp: implementation of the LMyDicomNet class. // ////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "DicomMWL.h" #include "MyDicomNet.h" #ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[]=__FILE__; #define new DEBUG_NEW #endif ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// #define CHECK_FOR_TIMEOUT() \ { \ if (m_nTimerCount > CGlobals::m_nTimerMax) \ { \ Close(); \ return; \ } \ m_nTimerCount = 0; \ } LMyDicomNet::LMyDicomNet(L_CHAR *pszPath, L_INT32 nMode):LDicomNet(pszPath, nMode) { m_pLog = NULL; m_nCommandType = NONE; m_nUniqueID = START_UNIQUE_ID; m_pTreeResult = NULL; m_nCountDS = 0; m_pStoreDS = NULL; m_strStorageClass = ""; m_strStorageInstance = ""; m_uTimerID = 0; } LMyDicomNet::~LMyDicomNet() { } //Send L_INT LMyDicomNet::Connect(L_CHAR *pszHostAddress, L_UINT nHostPort, L_CHAR *pszPeerAddress, L_UINT nPeerPort) { m_nTimerCount = 0; m_uTimerID = SetTimer(NULL, 0, 1000, TimerProc); m_pThis = this; if (m_pLog) m_pLog->Append("Send Connect"); L_INT nRet = LDicomNet::Connect(pszHostAddress, nHostPort, pszPeerAddress, nPeerPort); if (nRet != DICOM_SUCCESS) SendResult(DICOM_MSG_CONNECT_FAILED, 0); return nRet; } L_INT LMyDicomNet::Accept(LDicomNet *pNet) { if (m_pLog) m_pLog->Append("Send Accept"); return LDicomNet::Accept(pNet); } L_VOID LMyDicomNet::Close() { if (m_pLog) m_pLog->Append("Send Close"); LDicomNet::Close(); } L_INT LMyDicomNet::SendAssociateRequest(LDicomAssociate *pPDU) { if (m_pLog) m_pLog->Append("Send SendAssociateRequest"); return LDicomNet::SendAssociateRequest(pPDU); } L_INT LMyDicomNet::SendReleaseRequest() { if (m_pLog) m_pLog->Append("Send SendReleaseRequest"); return LDicomNet::SendReleaseRequest(); } L_INT LMyDicomNet::SendReleaseResponse() { if (m_pLog) m_pLog->Append("Send SendReleaseResponse"); return LDicomNet::SendReleaseResponse(); } L_INT LMyDicomNet::SendAbort(L_UCHAR nSource, L_UCHAR nReason) { if (m_pLog) m_pLog->Append("Send SendAbort"); return LDicomNet::SendAbort( nSource, nReason); } L_INT LMyDicomNet::SendCEchoRequest(L_UCHAR nPresentationID, L_UINT16 nMessageID, L_CHAR *pszClass) { if (m_pLog) m_pLog->Append("Send SendCEchoRequest"); return LDicomNet::SendCEchoRequest( nPresentationID, nMessageID, pszClass); } L_INT LMyDicomNet::SendCFindRequest(L_UCHAR nPresentationID, L_UINT16 nMessageID, L_CHAR *pszClass, L_UINT16 nPriority, LDicomDS *pDS) { if (m_pLog) m_pLog->Append("SendCFindRequest"); return LDicomNet::SendCFindRequest(nPresentationID, nMessageID, pszClass, nPriority, pDS); } L_INT LMyDicomNet::SendCStoreRequest(L_UCHAR nPresentationID, L_UINT16 nMessageID, L_CHAR *pszClass, L_CHAR *pszInstance, L_UINT16 nPriority, L_CHAR *pszMoveAE, L_UINT16 nMoveMessageID, LDicomDS *pDS) { if (m_pLog) m_pLog->Append("SendCStoreRequest"); return LDicomNet::SendCStoreRequest(nPresentationID, nMessageID, pszClass, pszInstance, nPriority, pszMoveAE, nMoveMessageID, pDS); } //Receive Events L_VOID LMyDicomNet::OnConnect(L_INT nError) { CHECK_FOR_TIMEOUT(); m_nCountDS = 0; if (m_pLog) { CString strMsg; strMsg.Format("OnConnect: Error[%d]", nError); m_pLog->Append(strMsg); } if (nError == DICOM_SUCCESS) { //Build an associate for C-ECHO LDicomAssociate Associate(TRUE); Associate.SetRequest(TRUE); Associate.SetVersion(1); //m_pAssociate.Default(); Associate.SetCalled((LPSTR)(LPCSTR)m_strServerAE); Associate.SetCalling((LPSTR)(LPCSTR)m_strClientAE); int nID; nID = 1; Associate.AddPresentation(nID, 0, UID_VERIFICATION_CLASS); Associate.AddTransfer(nID, UID_IMPLICIT_VR_LITTLE_ENDIAN); if (m_nCommandType == MODALITY_WORKLIST_FIND) { nID = 3; Associate.AddPresentation(nID, 0, UID_MODALITY_WORKLIST_FIND); Associate.AddTransfer(nID, UID_IMPLICIT_VR_LITTLE_ENDIAN); } else if (m_nCommandType == CSTORE) { nID = 3; BuildCStoreAssociate(Associate, nID); } SendAssociateRequest(&Associate); } else { SendResult(DICOM_MSG_CONNECT_FAILED, nError); } } L_VOID LMyDicomNet::OnAccept(L_INT nError) { CHECK_FOR_TIMEOUT(); if (m_pLog) { CString strMsg; strMsg.Format("OnAccept: Error[%d]", nError); m_pLog->Append(strMsg); } } L_VOID LMyDicomNet::OnClose (L_INT nError, LDicomNet *pNet) { if (m_pLog) { CString strMsg; strMsg.Format("OnClose: Error[%d]", nError); m_pLog->Append(strMsg); } } //Returns: // 0 -- failure // odd -- the presentation context ID L_UCHAR LMyDicomNet::VerifyClass(L_CHAR *pszID, LDicomAssociate *pPDU) { L_UCHAR nPresentationID = pPDU->FindAbstract(pszID); //nPresentationID must be odd--if 0, indicates failure if ((nPresentationID == 0) || (pPDU->GetResult(nPresentationID) != PDU_ACCEPT_RESULT_SUCCESS)) { CString strMsg; CString strTmp; strTmp.Format("Abstract Syntax[%s] Not Included in the Association", UID_VERIFICATION_CLASS); strMsg = strMsg + strTmp; if (m_pLog) m_pLog->Append(strMsg); return 0; } return nPresentationID; } L_VOID LMyDicomNet::DeleteOptionalModules(LDicomDS *pDS) { if (pDS) { pDS->DeleteModule(MODULE_PATIENT_RELATIONSHIP); pDS->DeleteModule(MODULE_PATIENT_IDENTIFICATION); pDS->DeleteModule(MODULE_PATIENT_DEMOGRAPHIC); pDS->DeleteModule(MODULE_PATIENT_MEDICAL); pDS->DeleteModule(MODULE_VISIT_RELATIONSHIP); pDS->DeleteModule(MODULE_VISIT_IDENTIFICATION); pDS->DeleteModule(MODULE_VISIT_STATUS); pDS->DeleteModule(MODULE_VISIT_ADMISSION); pDS->DeleteModule(MODULE_SCHEDULED_PROCEDURE_STEP); pDS->DeleteModule(MODULE_REQUESTED_PROCEDURE); pDS->DeleteModule(MODULE_IMAGING_SERVICE_REQUEST); } } L_VOID LMyDicomNet::CreateAndSetElement(LDicomDS *pDS, L_UINT32 uTag, L_UINT16 nVR, CString &strValue) { int nRet; if (strValue.GetLength() == 0) return; if (pDS) { pDICOMELEMENT pElement = NULL; pElement = pDS->FindFirstElement(NULL, uTag, FALSE); if (!pElement) pElement = pDS->InsertElement(NULL, FALSE, uTag, nVR, FALSE, 0); if (pElement) { pDS->FreeValue(pElement); nRet = pDS->SetConvertValue(pElement, (LPSTR)(LPCSTR)strValue, 1); } } } L_VOID LMyDicomNet::OnReceiveAssociateAccept(LDicomAssociate *pPDU) { CHECK_FOR_TIMEOUT(); if (m_pLog) m_pLog->Append("OnReceiveAssociateAccept"); L_UCHAR nPresentationID; switch (m_nCommandType) { case CECHO: { nPresentationID = VerifyClass(UID_VERIFICATION_CLASS, pPDU); if (!nPresentationID) return; SendCEchoRequest(nPresentationID, m_nUniqueID++, UID_VERIFICATION_CLASS); } break; case MODALITY_WORKLIST_FIND: { LDicomDS ds; nPresentationID = VerifyClass(UID_MODALITY_WORKLIST_FIND, pPDU); if (!nPresentationID) return; ds.InitDS(CLASS_MODALITY_WORKLIST, DS_METAHEADER_ABSENT | DS_IMPLICIT_VR | DS_LITTLE_ENDIAN ); // delete optional modules that we are not going to use // If you leave these modules, the items will be filled in and returned by the server //DeleteOptionalModules(&ds); // Build dataset if (CGlobals::m_nQueryType == CPage3::QUERY_PATIENT_BASE) { CreateAndSetElement(&ds, TAG_PATIENT_NAME, VR_PN, CGlobals::m_strPatientName); CreateAndSetElement(&ds, TAG_PATIENT_ID, VR_LO, CGlobals::m_strPatientID); CreateAndSetElement(&ds, TAG_ACCESSION_NUMBER, VR_SH, CGlobals::m_strAccessionNumber); CreateAndSetElement(&ds, TAG_REQUESTED_PROCEDURE_ID, VR_SH, CGlobals::m_strRequestedProcedureID); } else //QUERY_BROAD_MODALITY_WORK_LIST { CreateAndSetElement(&ds, TAG_SCHEDULED_PROCEDURE_STEP_START_DATE, VR_DA, CGlobals::m_strScheduleDate); CreateAndSetElement(&ds, TAG_MODALITY, VR_CS, CGlobals::m_strModality); } SendCFindRequest( nPresentationID, m_nUniqueID++, UID_MODALITY_WORKLIST_FIND, COMMAND_PRIORITY_MEDIUM, &ds); } break; case CSTORE: { nPresentationID = VerifyClass((LPSTR)(LPCSTR)m_strStorageClass, pPDU); if (!nPresentationID) return; L_INT nRet = SendCStoreRequest( nPresentationID, m_nUniqueID++, (LPSTR)(LPCSTR)m_strStorageClass, (LPSTR)(LPCSTR)m_strStorageInstance, COMMAND_PRIORITY_MEDIUM, "", 0, CGlobals::m_pDS); } break; } } L_VOID LMyDicomNet::OnReceiveCEchoResponse( L_UCHAR nPresentationID, L_UINT16 nMessageID, L_CHAR *pszClass, L_UINT16 nStatus) { CHECK_FOR_TIMEOUT(); if (m_pLog) { CString strMsg; strMsg.Format("OnReceiveCEchoResponse: Status[%s: 0x%x], PresentationID[%d], MessageID[%d], Class[%s] ", GetStatusString(nStatus), nStatus, nPresentationID, nMessageID, pszClass); m_pLog->Append(strMsg); } SendReleaseRequest(); } L_VOID LMyDicomNet::OnReceiveCFindResponse( L_UCHAR nPresentationID, L_UINT16 nMessageID, L_CHAR *pszClass, L_UINT16 nStatus, LDicomDS *pDS) { CHECK_FOR_TIMEOUT(); if (m_pLog) { CString strMsg; strMsg.Format("OnReceiveCFindResponse: Status[%s: 0x%x], PresentationID[%d], MessageID[%d], Class[%s]", GetStatusString(nStatus), nStatus, nPresentationID, nMessageID, pszClass); m_pLog->Append(strMsg); } if (m_pTreeResult) if ((nStatus == COMMAND_STATUS_PENDING_WARNING) || (nStatus == COMMAND_STATUS_PENDING)) m_pTreeResult->AddMWLItem(pDS, ++m_nCountDS); if (nStatus == COMMAND_STATUS_SUCCESS) { SendReleaseRequest(); } } L_VOID LMyDicomNet::OnReceiveCStoreResponse(L_UCHAR nPresentationID, L_UINT16 nMessageID, L_CHAR *pszClass, L_CHAR *pszInstance, L_UINT16 nStatus) { CHECK_FOR_TIMEOUT(); if (m_pLog) { CString strMsg; strMsg.Format("OnReceiveCStoreResponse: Status[%s: 0x%x], PresentationID[%d], MessageID[%d], Class[%s], Instance[%s]", GetStatusString(nStatus), nStatus, nPresentationID, nMessageID, pszClass, pszInstance); m_pLog->Append(strMsg); } SendResult(DICOM_MSG_CSTORE_RESULT, nStatus); SendReleaseRequest(); } L_VOID LMyDicomNet::OnReceiveAssociateReject(L_UCHAR nResult, L_UCHAR nSource, L_UCHAR nReason) { CHECK_FOR_TIMEOUT(); if (m_pLog) { CString strMsg; strMsg.Format("OnReceiveAssociateReject: Result[%d], Source[%d], Reason[%d]", nResult, nSource, nReason); m_pLog->Append(strMsg); } SendResult(DICOM_MSG_ASSOCIATE_REJECT, 0); Close(); } L_VOID LMyDicomNet::OnReceiveReleaseResponse() { CHECK_FOR_TIMEOUT(); if (m_pLog) { m_pLog->Append("OnReceiveReleaseResponse"); } Close(); SendResult(DICOM_MSG_SUCCESS, 0); } L_VOID LMyDicomNet::SendResult(int nResult, int nReason) { KillTimer(NULL, m_uTimerID); if (m_pWnd) m_pWnd->PostMessage(WM_DICOM_MSG, nResult, nReason); } L_VOID LMyDicomNet::OnSend(L_INT nError, L_UCHAR nType, L_UINT32 nBytes) { CHECK_FOR_TIMEOUT(); //if (m_pLog) //{ // m_pLog->Append("OnSend"); //} } typedef struct tagSTATUSSTRING { L_UINT16 nValue; L_CHAR * pszDesc; } STATUSSTRING, *LPSTATUSSTRING; STATUSSTRING StatusStringTable[] = { COMMAND_STATUS_SUCCESS ,"Success", COMMAND_STATUS_CANCEL ,"Cancel", COMMAND_STATUS_ATTRIBUTE_LIST_ERROR ,"Attribute List Error", COMMAND_STATUS_ATTRIBUTE_OUT_OF_RANGE ,"Attribute Value Out of Range", COMMAND_STATUS_CLASS_NOT_SUPPORTED ,"Class Not Supported", COMMAND_STATUS_CLASE_INSTANCE_CONFLICT ,"Class Instance conflict", COMMAND_STATUS_DUPLICATE_INSTANCE ,"Duplicate Instance", COMMAND_STATUS_DUPLICATE_INVOCATION ,"Duplicate invocation", COMMAND_STATUS_INVALID_ARGUMENT_VALUE ,"Invalid Argument Value", COMMAND_STATUS_INVALID_ATTRIBUTE_VALUE ,"Invalid Attribute Value", COMMAND_STATUS_INVALID_OBJECT_INSTANCE ,"Ivalid Object Instance", COMMAND_STATUS_MISSING_ATTRIBUTE ,"Missing Attribute", COMMAND_STATUS_MISSING_ATTRIBUTE_VALUE ,"Missing Attribute value", COMMAND_STATUS_MISTYPED_ARGUMENT ,"Mistyped Argument", COMMAND_STATUS_NO_SUCH_ARGUMENT ,"No Such Argument", COMMAND_STATUS_NO_SUCH_ATTRIBUTE ,"No Such Attribute", COMMAND_STATUS_NO_SUCH_EVENT_TYPE ,"No Such Event Type", COMMAND_STATUS_NO_SUCH_OBJECT_INSTANCE ,"No Such Object Instance", COMMAND_STATUS_NO_SUCH_CLASS ,"No Such Class", COMMAND_STATUS_PROCESSING_FAILURE ,"Proccesing Failure", COMMAND_STATUS_RESOURCE_LIMITATION ,"Resource Limitation", COMMAND_STATUS_UNRECOGNIZED_OPERATION ,"Unrecognized Operation", COMMAND_STATUS_PENDING ,"Pending", COMMAND_STATUS_PENDING_WARNING ,"Pending Warning", }; #define STATUS_STRING_TABLE_SIZE (sizeof(StatusStringTable)/sizeof(STATUSSTRING)) // Returns TRUE if successful CString LMyDicomNet::GetStatusString(L_UINT16 nStatus) { CString csStatus = "Unknown"; int i; for (i=0; iFindFirstElement(NULL, TAG_MEDIA_STORAGE_SOP_CLASS_UID, TRUE); if (pElement != NULL) pszText = CGlobals::m_pDS->GetStringValue(pElement, 0, 1); if (pszText == NULL) { pElement = CGlobals::m_pDS->FindFirstElement(NULL, TAG_SOP_CLASS_UID, TRUE); if (pElement != NULL) pszText = CGlobals::m_pDS->GetStringValue(pElement, 0, 1); } if (pszText != NULL) strClass = pszText; m_strStorageClass = strClass; pElement = CGlobals::m_pDS->FindFirstElement(NULL, TAG_SOP_INSTANCE_UID, TRUE); if (pElement != NULL) pszText = CGlobals::m_pDS->GetStringValue(pElement, 0, 1); if (pszText != NULL) strInstance = pszText; m_strStorageInstance = strInstance; pElement = CGlobals::m_pDS->FindFirstElement(NULL, TAG_TRANSFER_SYNTAX_UID, TRUE); if (pElement != NULL) pszText = CGlobals::m_pDS->GetStringValue(pElement, 0, 1); if (pszText != NULL) strTransfer = pszText; Associate.AddPresentation(uID, 0, (LPSTR)(LPCTSTR)strClass); Associate.AddTransfer(uID, (LPSTR)(LPCTSTR)strTransfer); } L_UINT LMyDicomNet::m_uTimerID = 0; int LMyDicomNet::m_nTimerCount = 0; CWnd * LMyDicomNet::m_pWnd = NULL; LMyDicomNet * LMyDicomNet::m_pThis = NULL; //****************** Timer Proc for timeout mechanism VOID CALLBACK LMyDicomNet::TimerProc( HWND hwnd, // handle of window for timer messages UINT uMsg, // WM_TIMER message UINT idEvent, // timer identifier DWORD dwTime // current system time ) { if (m_nTimerCount > CGlobals::m_nTimerMax) { KillTimer(NULL, m_uTimerID); if (m_pThis) { m_pThis->Close(); m_pThis = NULL; } SendResult(DICOM_MSG_TIMEOUT, 0); } m_nTimerCount++; }