// StrSCU.cpp: implementation of the LStoreScu class. #include "stdafx.h" #include "StrSCU.h" // Construction LStoreScu::LStoreScu(L_CHAR* pszPath, L_UINT32 nMode) : LDicomNet(pszPath, nMode) { m_pszServerName = NULL; m_pszClientName = NULL; lstrcpy(m_szStorageClass, ""); lstrcpy(m_szStorageInstance, ""); m_uCompression = 0; m_pFiles = NULL; m_pPosFile = NULL; } // Destruction LStoreScu::~LStoreScu() { // Free any allocated memory if (m_pszClientName) { delete [] m_pszClientName; } if (m_pszServerName) { delete [] m_pszServerName; } RemoveAllFiles(); } L_INT LStoreScu::AddFile(L_CHAR* pszFilename) { if (!pszFilename) return DICOM_ERROR_PARAMETER; pCURFILE pNewFile, pNextFile; if (m_pFiles) { pNextFile = m_pFiles; while (pNextFile) { if (!pNextFile->pNextFile) break; pNextFile = pNextFile->pNextFile; } pNextFile->pNextFile = new CURFILE; pNewFile = pNextFile->pNextFile; } else { m_pFiles = new CURFILE; pNewFile = m_pFiles; } if (!pNewFile) return DICOM_ERROR_MEMORY; pNewFile->pNextFile = NULL; lstrcpyn(pNewFile->szFilename, pszFilename, sizeof(pNewFile->szFilename)); return DICOM_SUCCESS; } L_VOID LStoreScu::RemoveAllFiles() { pCURFILE pNextFile; while (m_pFiles) { pNextFile = m_pFiles->pNextFile; delete m_pFiles; m_pFiles = pNextFile; } } // Close the connection L_VOID LStoreScu::CloseConnection() { Close(); OnStatus(STR_CONNECTION_CLOSED, 0); } // Get the server and client information in order to start the verification process L_INT LStoreScu::DoStore(L_CHAR* pszServerName, L_CHAR* pszClientName, L_CHAR* pszServerIP, L_UINT uCompression,L_UINT nServerPort) { if (m_pszServerName) { delete [] m_pszServerName; m_pszServerName = NULL; } if (m_pszClientName) { delete [] m_pszClientName; m_pszClientName = NULL; } if (pszServerName) { m_pszServerName = new L_CHAR[lstrlen(pszServerName) + 1]; if (!m_pszServerName) { return DICOM_ERROR_MEMORY; } // The SCP AE name lstrcpy(m_pszServerName, pszServerName); } if (pszClientName) { m_pszClientName = new L_CHAR[lstrlen(pszClientName) + 1]; if (!m_pszClientName) { return DICOM_ERROR_MEMORY; } // The SCU AE name lstrcpy(m_pszClientName,pszClientName); } m_uCompression = uCompression; L_INT nRet; // Do the connection to the server nRet = Connect(NULL, 0, pszServerIP, nServerPort); if (nRet != DICOM_SUCCESS) { OnStatus(STR_CONNECT_FAILED, nRet); return nRet; } return 0; } // OnConnect() client receives this event from the SCP L_VOID LStoreScu::OnConnect(L_INT nError) { if (nError != DICOM_SUCCESS) { // Failed connection OnStatus(STR_CONNECT_FAILED, nError); TerminateStorage(); return; } // Succeeded connection OnStatus(STR_CONNECT_SUCCEEDED, 0); // Build the association for the first selected file m_pPosFile = m_pFiles; BuildAssociation(); } L_VOID LStoreScu::BuildAssociation() { if (m_pPosFile) { // Build the association for the C-Store LDicomAssociate StoreAssociate(TRUE); // Send the name of the current file OnProgressFiles(m_pPosFile->szFilename); L_INT nRet; // Set the version nRet = StoreAssociate.SetVersion(1); if (nRet != 0) { OnStatus(STR_DICOM_ERROR, nRet); TerminateStorage(); return; } // Set called application title nRet = StoreAssociate.SetCalled(m_pszServerName ? m_pszServerName : ""); if (nRet != 0) { OnStatus(STR_DICOM_ERROR, nRet); TerminateStorage(); return; } // Set calling application title nRet = StoreAssociate.SetCalling(m_pszClientName ? m_pszClientName : ""); if (nRet != 0) { OnStatus(STR_DICOM_ERROR, nRet); TerminateStorage(); return; } // Set maximum length nRet = StoreAssociate.SetMaxLength(TRUE, 0x100000); if (nRet != 0) { OnStatus(STR_DICOM_ERROR, nRet); TerminateStorage(); return; } pDICOMELEMENT pDicomElement; nRet = m_DicomDS.LoadDS(m_pPosFile->szFilename, 0); if (nRet != 0) { OnStatus(STR_DICOM_ERROR, nRet); TerminateStorage(); return; } L_CHAR* pszSOPClassUID = NULL; pDicomElement = m_DicomDS.FindFirstElement(NULL, TAG_MEDIA_STORAGE_SOP_CLASS_UID, FALSE); if (pDicomElement) pszSOPClassUID = m_DicomDS.GetStringValue(pDicomElement, 0, 1); if (lstrlen(pszSOPClassUID) == 0) { pDicomElement = m_DicomDS.FindFirstElement(NULL, TAG_SOP_CLASS_UID, FALSE); if (pDicomElement) pszSOPClassUID = m_DicomDS.GetStringValue(pDicomElement, 0, 1); } if (lstrlen(pszSOPClassUID) == 0) pszSOPClassUID = "1.1.1.1"; lstrcpyn(m_szStorageClass, pszSOPClassUID, sizeof(m_szStorageClass)) ; L_CHAR* pszText = NULL; pDicomElement = m_DicomDS.FindFirstElement(NULL, TAG_SOP_INSTANCE_UID, FALSE); if (pDicomElement != NULL) pszText = m_DicomDS.GetStringValue(pDicomElement, 0, 1); if (lstrlen(pszText) == 0) pszText = "998.998.1.19950214.94000.1.102"; lstrcpyn(m_szStorageInstance, pszText, sizeof(m_szStorageInstance)); L_INT nPresID = 1; nRet = StoreAssociate.AddPresentation(nPresID, 0, m_szStorageClass); if (nRet != 0) { OnStatus(STR_DICOM_ERROR, nRet); TerminateStorage(); return; } // Add the transfer syntax for the storage service class L_CHAR* pszTransfer; L_CHAR* pszDefTrans = UID_IMPLICIT_VR_LITTLE_ENDIAN; // Default transfer syntax if (m_uCompression != STR_DONT_RECOMPRESS) { switch (m_uCompression) { case STR_J2K_LOSSY: pszTransfer = UID_JPEG2000; break; case STR_J2KLOSSLESS: pszTransfer = UID_JPEG2000_LOSSLESS_ONLY; break; case STR_JPEG_LOSSY: pszTransfer = UID_JPEG_BASELINE_1; break; case STR_JPEG_LOSSLESS: pszTransfer = UID_JPEG_LOSSLESS_NONHIER_14; break; }; nRet = StoreAssociate.AddTransfer(nPresID, pszTransfer); if (nRet != 0) { OnStatus(STR_DICOM_ERROR, nRet); TerminateStorage(); return; } } else { pDicomElement = NULL; pDicomElement = m_DicomDS.FindFirstElement(NULL, TAG_TRANSFER_SYNTAX_UID, FALSE); if (pDicomElement != NULL) { // Check if this transfer syntax is as the default transfere syntax pszTransfer = m_DicomDS.GetStringValue(pDicomElement, 0, 1); if (lstrlen(pszTransfer) != 0) { if ((lstrcmp(pszTransfer, pszDefTrans)) != 0) { nRet = StoreAssociate.AddTransfer(nPresID, pszTransfer); // Adding the transfer syntax used in the image if (nRet != 0) { OnStatus(STR_DICOM_ERROR, nRet); TerminateStorage(); return; } } } } } // Adding the default transfer syntax nRet = StoreAssociate.AddTransfer(nPresID, pszDefTrans); if (nRet != 0) { OnStatus(STR_DICOM_ERROR, nRet); TerminateStorage(); return; } // Add the Implementation Version nRet = StoreAssociate.SetImplementVersion(TRUE, IMPLEMENTATION_VERSION_NAME); if (nRet != 0) { OnStatus(STR_DICOM_ERROR, nRet); TerminateStorage(); return; } // Add the Implementation Class nRet = StoreAssociate.SetImplementClass(TRUE, IMPLEMENTATION_CLASS_UID); if (nRet != 0) { OnStatus(STR_DICOM_ERROR, nRet); TerminateStorage(); return; } // Sending the associate request OnStatus(STR_SEND_ASSOCIATION_REQUEST, 0); nRet = SendAssociateRequest(&StoreAssociate); if (nRet != 0) { // Error sending the association request OnStatus(STR_DICOM_ERROR, nRet); TerminateStorage(); } } } // Receive the acceptance of the association L_VOID LStoreScu::OnReceiveAssociateAccept(LDicomAssociate *pPDU) { L_UCHAR uPresID; L_CHAR* pszReturnTrans; // Server accept the association OnStatus(STR_RECEIVE_ASSOCIATE_ACCEPT, 0); // Check if the sent abstfract syntax is accepted uPresID = pPDU->FindAbstract(m_szStorageClass); if ((uPresID == 0) || (pPDU->GetResult(uPresID) != PDU_ACCEPT_RESULT_SUCCESS)) { // The abstract syntax is NOT supported OnStatus(STR_ABSTRACT_SYNTAX_NOT_SUPPORTED, 0); TerminateStorage(); return; } // Get the accepted transfer syntax pszReturnTrans = pPDU->GetTransfer(1, 0); L_INT nRet; // Change the transfer syntax to the accepted one nRet = m_DicomDS.ChangeTransferSyntax(pszReturnTrans, 2, 0); if (nRet != 0) { OnStatus(STR_DICOM_ERROR, nRet); TerminateStorage(); return; } // Sneding the C-Store request OnStatus(STR_SEND_CSTORE_REQUEST, 0); nRet = SendCStoreRequest(uPresID, 1, m_szStorageClass, m_szStorageInstance, COMMAND_PRIORITY_MEDIUM, "", 0, &m_DicomDS); if (nRet != 0) { OnStatus(STR_DICOM_ERROR, nRet); TerminateStorage(); } } // Receive the rejection of the association L_VOID LStoreScu::OnReceiveAssociateReject(L_UCHAR nResult, L_UCHAR nSource, L_UCHAR nReason) { // Server rejects this association OnStatus(STR_RECEIVE_ASSOCIATE_REJECT, 0); // Close the connection CloseConnection(); } // Receive the acceptance for the releasing of the association L_VOID LStoreScu::OnReceiveReleaseResponse() { OnStatus(STR_RECEIVE_RELEASE_RESPONSE, 0); if (!m_pPosFile) return; // Get the next file structure m_pPosFile = m_pPosFile->pNextFile; // Build the association for the next file if (m_pPosFile) { BuildAssociation(); return; } // Close the association CloseConnection(); } // Receiving Response for the C-Store form the SCP L_VOID LStoreScu::OnReceiveCStoreResponse(L_UCHAR nPresentationID, L_UINT16 nMessageID, L_CHAR *pszClass, L_CHAR *pszInstance, L_UINT16 nStatus) { OnStatus(STR_RECEIVE_CSTORE_RESPONSE, nStatus); // Send a Release Request message L_INT nRet; OnStatus(STR_SEND_RELEASE_REQUEST, 0); nRet = SendReleaseRequest(); if (nRet != 0) { // Error sending release request OnStatus(STR_DICOM_ERROR, nRet); TerminateStorage(); return; } } // Terminate the storage process L_VOID LStoreScu::TerminateStorage() { if (IsConnected()) { if (IsAssociated()) { SendAbort(PDU_ABORT_SOURCE_USER, 0); } // Close the connection CloseConnection(); } OnStatus(STR_PROCESS_TERMINATED, 0); } L_VOID LStoreScu::OnStatus(L_UINT uStatus, L_INT nErrorCode) { } L_VOID LStoreScu::OnProgressFiles(L_CHAR* pszFileName) { }