#include "StrMain.h" // Defines // Compression types #define STR_DONT_RECOMPRESS 0 // Leave image compression (Don't re-compress) #define STR_J2K_LOSSY 1 // J2K Lossy #define STR_J2KLOSSLESS 2 // J2K Lossless #define STR_JPEG_LOSSY 3 // JPEG Lossy #define STR_JPEG_LOSSLESS 4 // JPEG Lossless #define STR_CONNECT_FAILED 1 // Connect operation failed #define STR_CONNECT_SUCCEEDED 2 // Connect operation succeeded #define STR_SEND_ASSOCIATION_REQUEST 3 // Sending assocaition request #define STR_RECEIVE_ASSOCIATE_ACCEPT 4 // Receiving association accept #define STR_RECEIVE_ASSOCIATE_REJECT 5 // Receiving association reject #define STR_ABSTRACT_SYNTAX_NOT_SUPPORTED 6 // Abstract Syntax not supported #define STR_SEND_CSTORE_REQUEST 7 // Sending C-STORE request #define STR_RECEIVE_CSTORE_RESPONSE 8 // Receiving C-STORE response #define STR_CONNECTION_CLOSED 9 // Closing connection #define STR_PROCESS_TERMINATED 10 // Storage has been terminated #define STR_SEND_RELEASE_REQUEST 11 // Sending release request #define STR_RECEIVE_RELEASE_RESPONSE 12 // Receiving release response #define STR_DICOM_ERROR 13 // General DICOM Error // The implementation Class #define IMPLEMENTATION_CLASS_UID "1.2.840.114257.1123456" // The implementation Version #define IMPLEMENTATION_VERSION_NAME "1" // Timer Identifier #define IDT_MY_TIMER 1 struct { L_UINT uStatusID; // ID of the status message L_CHAR* pszDescription; // The description of the status message L_BOOL bFinish; // Whether the process is to be finished or not } StatusArray[] = { STR_CONNECT_FAILED, "Connect operation failed", TRUE, STR_CONNECT_SUCCEEDED, "Connect operation succeeded", FALSE, STR_SEND_ASSOCIATION_REQUEST, "Sending assocaition request", FALSE, STR_RECEIVE_ASSOCIATE_ACCEPT, "Receiving association accept", FALSE, STR_RECEIVE_ASSOCIATE_REJECT, "Receiving association reject", TRUE, STR_ABSTRACT_SYNTAX_NOT_SUPPORTED, "Abstract Syntax not supported", TRUE, STR_SEND_CSTORE_REQUEST, "Sending C-STORE request", FALSE, STR_RECEIVE_CSTORE_RESPONSE, "**** Storage (C-STORE) completed successfully ****", TRUE, STR_CONNECTION_CLOSED, "Closing connection", TRUE, STR_PROCESS_TERMINATED, "Storage has been terminated", TRUE, STR_SEND_RELEASE_REQUEST, "Sending release request", FALSE, STR_RECEIVE_RELEASE_RESPONSE, "Receiving release response", TRUE, STR_DICOM_ERROR , "General DICOM Error", TRUE, }; LRESULT CALLBACK ProgressDlgProc(HWND, UINT, WPARAM, LPARAM); L_VOID L_EXPORT OnConnectCallback(HDICOMNET hNet, L_INT nError, L_VOID *pUserData); L_VOID L_EXPORT OnReceiveAssociateAcceptCallback(HDICOMNET hNet, HDICOMPDU hPDU, L_VOID *pUserData); L_VOID L_EXPORT OnReceiveAssociateRejectCallback(HDICOMNET hNet, L_UCHAR nResult, L_UCHAR nSource, L_UCHAR nReason, L_VOID *pUserData); L_VOID L_EXPORT OnReceiveReleaseResponseCallback(HDICOMNET hNet, L_VOID *pUserData); L_VOID L_EXPORT OnReceiveCStoreResponseCallback(HDICOMNET hNet, L_UCHAR nPresentationID, L_UINT16 nMessageID, L_CHAR *pszClass, L_CHAR *pszInstance, L_UINT16 nStatus, L_VOID *pUserData); L_VOID BuildAssociation(HWND hDlg); L_VOID OnStatus(HWND hDlg, L_UINT uStatus, L_INT nErrorCode); L_VOID OnProgressFiles(HWND hDlg, L_CHAR* pszFileName); L_VOID SetMyCallbacks(HDICOMNET hNet, HWND hWndDlg); L_VOID TerminateStore(HWND hDlg); L_VOID CloseConnection(HWND hDlg, HDICOMNET hNet); L_INT DoStore(HWND hMainDlg); L_CHAR* GetStatusText(HWND hMainDlg, L_UINT uStatusConst); HDICOMNET ghSTRDicomNet; HDICOMDS ghDicomDS; extern pCURFILE gpFiles; pCURFILE gpPosFile; L_CHAR gszStorageClass[128]; L_CHAR gszStorageInstance[128]; L_UINT uCountTimer; extern L_CHAR gszServerName[64]; extern L_CHAR gszPeerIP[64]; extern L_CHAR gszClientName[64]; extern L_UINT guServerPort; extern L_UINT guCompression; extern L_UINT guTimeOut; // Progress Dialog Procedure LRESULT CALLBACK ProgressDlgProc(HWND hMainDlg, UINT uiMessage, WPARAM wParam, LPARAM lParam) { L_CHAR szStatus[5000]; switch (uiMessage) { case WM_INITDIALOG: ghSTRDicomNet = L_DicomCreateNet(NULL, DICOM_SECURE_NONE); ghDicomDS = L_DicomCreateDS(NULL); // Set the callback functions SetMyCallbacks(ghSTRDicomNet, hMainDlg); // Open the animation control Animate_Open(GetDlgItem(hMainDlg, IDC_ANIMATE), MAKEINTRESOURCE(IDR_WAITAVI)); Animate_Play(GetDlgItem(hMainDlg, IDC_ANIMATE), 0, -1, -1); // Set the timer if (guTimeOut > 0) { uCountTimer = 0; SetTimer(hMainDlg, IDT_MY_TIMER, 1000, NULL); } if (DoStore(hMainDlg) != DICOM_SUCCESS) { EndDialog(hMainDlg, 0); } return 0; case WM_COMMAND: switch (LOWORD(wParam)) { case ID_BUT_CANCEL: // Terminate the process TerminateStore(hMainDlg); EndDialog(hMainDlg, 0); break; } return 0; case WM_TIMER: if (wParam == IDT_MY_TIMER) { // Process the time-out timer uCountTimer++; // Check if the time out is expired if (uCountTimer > guTimeOut) { // Get the text in the status edit box GetDlgItemText(GetParent(hMainDlg), IDC_EDIT_STATUS, szStatus, sizeof(szStatus)); wsprintf(szStatus, "%sTime-out expired. The process will be terminated!\r\n", szStatus); // Show the status in the staus edit box SetDlgItemText(GetParent(hMainDlg), IDC_EDIT_STATUS, szStatus); // Terminate the process TerminateStore(hMainDlg); EndDialog(hMainDlg, 0); } return 0; } break; case WM_DESTROY: Animate_Stop(GetDlgItem(hMainDlg, IDC_ANIMATE)); Animate_Close(GetDlgItem(hMainDlg, IDC_ANIMATE)); L_DicomFreeNet(ghSTRDicomNet); L_DicomFreeDS(ghDicomDS); return 0; case WM_CLOSE: TerminateStore(hMainDlg); EndDialog(hMainDlg, 0); return 0; } return 0; } L_INT DoStore(HWND hDlg) { L_UINT nRet; // Do the connection to the server nRet = L_DicomConnect(ghSTRDicomNet, NULL, 0, gszPeerIP, guServerPort); if (nRet != DICOM_SUCCESS) { OnStatus(hDlg, STR_CONNECT_FAILED, nRet); return nRet; } return DICOM_SUCCESS; } L_VOID BuildAssociation(HWND hDlg) { HDICOMPDU hSTRPDU; pDICOMELEMENT pDicomElement; L_UINT nRet; L_CHAR* pszSOPClassUID; L_CHAR* pszText; L_CHAR* pszTransfer; L_CHAR* pszDefTrans = UID_IMPLICIT_VR_LITTLE_ENDIAN; // Default transfer syntax L_UCHAR nPresID = 1; if (!gpPosFile) return; // Build the association request hSTRPDU = L_DicomCreateAssociate(TRUE); // Display the name of the current file OnProgressFiles(hDlg, gpPosFile->szFilename); // Set version nRet = L_DicomSetVersion(hSTRPDU, 1); if (nRet != DICOM_SUCCESS) { // Status OnStatus(hDlg, STR_DICOM_ERROR, nRet); TerminateStore(hDlg); L_DicomFreeAssociate(hSTRPDU); return; } // Set called application title nRet = L_DicomSetCalled(hSTRPDU, gszServerName); if (nRet != DICOM_SUCCESS) { // Status OnStatus(hDlg, STR_DICOM_ERROR, nRet); TerminateStore(hDlg); L_DicomFreeAssociate(hSTRPDU); return; } // Set calling application title nRet = L_DicomSetCalling(hSTRPDU, gszClientName); if (nRet != DICOM_SUCCESS) { OnStatus(hDlg, STR_DICOM_ERROR, nRet); TerminateStore(hDlg); L_DicomFreeAssociate(hSTRPDU); return; } // Set maximum length nRet = L_DicomSetMaxLength(hSTRPDU, TRUE, 0x100000); if (nRet != DICOM_SUCCESS) { OnStatus(hDlg, STR_DICOM_ERROR, nRet); TerminateStore(hDlg); L_DicomFreeAssociate(hSTRPDU); return; } nRet = L_DicomLoadDS(ghDicomDS, gpPosFile->szFilename, 0); if (nRet != DICOM_SUCCESS) { OnStatus(hDlg, STR_DICOM_ERROR, nRet); TerminateStore(hDlg); L_DicomFreeAssociate(hSTRPDU); return; } pszSOPClassUID = NULL; pDicomElement = L_DicomFindFirstElement(ghDicomDS, NULL, TAG_MEDIA_STORAGE_SOP_CLASS_UID, FALSE); if (pDicomElement) pszSOPClassUID = L_DicomGetStringValue(ghDicomDS, pDicomElement, 0, 1); if (lstrlen(pszSOPClassUID) == 0) { pDicomElement = L_DicomFindFirstElement(ghDicomDS, NULL, TAG_SOP_CLASS_UID, FALSE); if (pDicomElement) pszSOPClassUID = L_DicomGetStringValue(ghDicomDS, pDicomElement, 0, 1); } if (lstrlen(pszSOPClassUID) == 0) pszSOPClassUID = "1.1.1.1"; lstrcpyn(gszStorageClass, pszSOPClassUID, sizeof(gszStorageClass)); pszText = NULL; pDicomElement = L_DicomFindFirstElement(ghDicomDS, NULL, TAG_SOP_INSTANCE_UID, FALSE); if (pDicomElement != NULL) pszText = L_DicomGetStringValue(ghDicomDS, pDicomElement, 0, 1); if (lstrlen(pszText) == 0) pszText = "998.998.1.19950214.94000.1.102"; lstrcpyn(gszStorageInstance, pszText, sizeof(gszStorageInstance)); nRet = L_DicomAddPresentation(hSTRPDU, nPresID, 0, gszStorageClass); if (nRet != DICOM_SUCCESS) { OnStatus(hDlg ,STR_DICOM_ERROR, nRet); TerminateStore(hDlg); L_DicomFreeAssociate(hSTRPDU); return; } // Add the transfer syntax for the storage service class if (guCompression != STR_DONT_RECOMPRESS) { switch (guCompression) { 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 = L_DicomAddTransfer(hSTRPDU, nPresID, pszTransfer); if (nRet != DICOM_SUCCESS) { OnStatus(hDlg, STR_DICOM_ERROR, nRet); TerminateStore(hDlg); L_DicomFreeAssociate(hSTRPDU); return; } } else { pDicomElement = L_DicomFindFirstElement(ghDicomDS, NULL, TAG_TRANSFER_SYNTAX_UID, FALSE); if (pDicomElement != NULL) { // Check if this transfer syntax is the default transfer syntax pszTransfer = L_DicomGetStringValue(ghDicomDS, pDicomElement, 0, 1); if (lstrlen(pszTransfer) != 0) { if ((lstrcmp(pszTransfer, pszDefTrans)) != 0) { nRet = L_DicomAddTransfer(hSTRPDU, nPresID, pszTransfer); // Adding the transfer syntax used in the image if (nRet != DICOM_SUCCESS) { OnStatus(hDlg, STR_DICOM_ERROR, nRet); TerminateStore(hDlg); L_DicomFreeAssociate(hSTRPDU); return; } } } } } // Adding the default transfer syntax nRet = L_DicomAddTransfer(hSTRPDU, nPresID, pszDefTrans); if (nRet != DICOM_SUCCESS) { OnStatus(hDlg, STR_DICOM_ERROR, nRet); TerminateStore(hDlg); L_DicomFreeAssociate(hSTRPDU); return; } // Add the Implementation Version nRet = L_DicomSetImplementVersion(hSTRPDU, TRUE, IMPLEMENTATION_VERSION_NAME); if (nRet != DICOM_SUCCESS) { OnStatus(hDlg, STR_DICOM_ERROR, nRet); TerminateStore(hDlg); L_DicomFreeAssociate(hSTRPDU); return; } // Add the Implementation Class nRet = L_DicomSetImplementClass(hSTRPDU, TRUE, IMPLEMENTATION_CLASS_UID); if (nRet != DICOM_SUCCESS) { OnStatus(hDlg, STR_DICOM_ERROR, nRet); TerminateStore(hDlg); L_DicomFreeAssociate(hSTRPDU); return; } // Sending the associate request OnStatus(hDlg, STR_SEND_ASSOCIATION_REQUEST, 0); nRet = L_DicomSendAssociateRequest(ghSTRDicomNet, hSTRPDU); if (nRet != DICOM_SUCCESS) { // Error sending the association request OnStatus(hDlg, STR_DICOM_ERROR, nRet); TerminateStore(hDlg); L_DicomFreeAssociate(hSTRPDU); return; } L_DicomFreeAssociate(hSTRPDU); } L_VOID OnStatus(HWND hDlg, L_UINT uStatus, L_INT nErrorCode) { HWND hStatusEdit; L_CHAR szStatus[200] = ""; L_CHAR* pszTempStat = NULL; L_CHAR* pszReturned = NULL; LRESULT nCurPos; L_INT nSize; // Get the current status related text if (uStatus == STR_DICOM_ERROR) { // General DICOM error wsprintf(szStatus, "DICOM error. The process will be terminated! --- Error code is: %i\r\n", nErrorCode); } else { if (uStatus == STR_RECEIVE_CSTORE_RESPONSE) { if (nErrorCode != COMMAND_STATUS_SUCCESS) { wsprintf(szStatus, "*** Status: 0x%04x ***", nErrorCode); } else { if (pszReturned = GetStatusText(hDlg, uStatus)) wsprintf(szStatus, "%s", pszReturned); } } else { if (pszReturned = GetStatusText(hDlg, uStatus)) wsprintf(szStatus, "%s", pszReturned); } } hStatusEdit = GetDlgItem(GetParent(hDlg), IDC_EDIT_STATUS); nSize = GetWindowTextLength(hStatusEdit) + lstrlen(szStatus) + 4; pszTempStat = (L_CHAR*) malloc(nSize); if (!pszTempStat) return; // Get the text in the status edit box GetDlgItemText(GetParent(hDlg), IDC_EDIT_STATUS, pszTempStat, nSize); wsprintf(pszTempStat, "%s%s\r\n", pszTempStat, szStatus); // Show the status in the staus edit box SetDlgItemText(GetParent(hDlg), IDC_EDIT_STATUS, pszTempStat); free(pszTempStat); // Vertical scroll nCurPos = SendMessage(hStatusEdit, EM_LINEFROMCHAR, GetWindowTextLength(hStatusEdit) - 1 , 0); SendMessage(hStatusEdit, EM_LINESCROLL, 0, nCurPos); // Check to close the progress dialog if ((uStatus == STR_CONNECTION_CLOSED) || (uStatus == STR_CONNECT_FAILED) || (uStatus == STR_PROCESS_TERMINATED)) EndDialog(hDlg, 0); } L_CHAR* GetStatusText(HWND hMainDlg, L_UINT uStatusConst) { L_INT iCounter; L_INT iLength = sizeof(StatusArray) / sizeof(StatusArray[0]); for (iCounter = 0; iCounter < iLength - 1; iCounter++) { if (StatusArray[iCounter].uStatusID == uStatusConst) { return StatusArray[iCounter].pszDescription; } } return NULL; } L_VOID SetMyCallbacks(HDICOMNET hNet, HWND hWndDlg) { DICOMNETCALLBACK MyCallbacks; memset(&MyCallbacks, 0, sizeof(DICOMNETCALLBACK)); MyCallbacks.pfnConnect = OnConnectCallback; MyCallbacks.pfnReceiveAssociateAccept = OnReceiveAssociateAcceptCallback; MyCallbacks.pfnReceiveAssociateReject = OnReceiveAssociateRejectCallback; MyCallbacks.pfnReceiveReleaseResponse = OnReceiveReleaseResponseCallback; MyCallbacks.pfnReceiveCStoreResponse = OnReceiveCStoreResponseCallback; MyCallbacks.pUserData = hWndDlg; L_DicomSetCallback(hNet, &MyCallbacks); } L_VOID L_EXPORT OnConnectCallback(HDICOMNET hNet, L_INT nError, L_VOID *pUserData) { HWND hDlg; hDlg = (HWND) pUserData; if (nError != DICOM_SUCCESS) { // Failed connection OnStatus(hDlg, STR_CONNECT_FAILED, nError); TerminateStore(hDlg); return; } // Succeeded connection OnStatus(hDlg, STR_CONNECT_SUCCEEDED, 0); // Build the association for the first selected file gpPosFile = gpFiles; BuildAssociation(hDlg); } L_VOID L_EXPORT OnReceiveAssociateAcceptCallback(HDICOMNET hNet, HDICOMPDU hPDU, L_VOID *pUserData) { HWND hDlg; L_UCHAR uPresID; L_CHAR* pszReturnTrans; L_INT nRet; hDlg=(HWND)pUserData; // Server accept the association OnStatus(hDlg, STR_RECEIVE_ASSOCIATE_ACCEPT, 0); // Check if the sent abstfract syntax is accepted uPresID = L_DicomFindAbstract(hPDU, gszStorageClass); if ((uPresID == 0) || (L_DicomGetResult(hPDU, uPresID) != PDU_ACCEPT_RESULT_SUCCESS)) { // The abstract syntax is NOT supported OnStatus(hDlg, STR_ABSTRACT_SYNTAX_NOT_SUPPORTED, 0); TerminateStore(hDlg); return; } // Get the accepted transfer syntax pszReturnTrans = L_DicomGetTransfer(hPDU, 1, 0); // Change the transfer syntax to the accepted one nRet = L_DicomChangeTransferSyntax(ghDicomDS, pszReturnTrans, 2, 0); if (nRet != DICOM_SUCCESS) { OnStatus(hDlg, STR_DICOM_ERROR, nRet); TerminateStore(hDlg); return; } // Storage supported // Sneding the C-STORE request OnStatus(hDlg, STR_SEND_CSTORE_REQUEST, 0); nRet = L_DicomSendCStoreRequest(hNet, uPresID, 1, gszStorageClass, gszStorageInstance, COMMAND_PRIORITY_MEDIUM, "", 0, ghDicomDS); if (nRet != DICOM_SUCCESS) { // Error sending the CSTORE Request OnStatus(hDlg, STR_DICOM_ERROR, nRet); TerminateStore(hDlg); return; } } L_VOID L_EXPORT OnReceiveAssociateRejectCallback(HDICOMNET hNet, L_UCHAR nResult, L_UCHAR nSource, L_UCHAR nReason, L_VOID *pUserData) { // OnReceiveAssociateReject call back function // Server rejects this association HWND hDlg; hDlg=(HWND)pUserData; OnStatus(hDlg, STR_RECEIVE_ASSOCIATE_REJECT, 0); // Close the connection CloseConnection(hDlg, hNet); } L_VOID L_EXPORT OnReceiveReleaseResponseCallback(HDICOMNET hNet, L_VOID *pUserData) { // OnReceiveReleaseResponse call back function HWND hDlg; hDlg=(HWND)pUserData; OnStatus(hDlg, STR_RECEIVE_RELEASE_RESPONSE, 0); if (!gpPosFile) return; // The next file gpPosFile = (CURFILE*) gpPosFile->pNextFile; // Build the association for the next file if (gpPosFile) { BuildAssociation(hDlg); return; } // Close the association CloseConnection(hDlg, hNet); EndDialog(hDlg, 0); } L_VOID L_EXPORT OnReceiveCStoreResponseCallback(HDICOMNET hNet, L_UCHAR nPresentationID, L_UINT16 nMessageID, L_CHAR *pszClass, L_CHAR *pszInstance, L_UINT16 nStatus, L_VOID *pUserData) { // OnReceiveCStoreResponseCallback call back function HWND hDlg; L_INT nRet; hDlg=(HWND)pUserData; OnStatus(hDlg, STR_RECEIVE_CSTORE_RESPONSE, nStatus); // Send a Release Request message OnStatus(hDlg, STR_SEND_RELEASE_REQUEST, 0); nRet = L_DicomSendReleaseRequest(hNet); if (nRet != DICOM_SUCCESS) { // Error sending release request OnStatus(hDlg, STR_DICOM_ERROR, nRet); TerminateStore(hDlg); return; } } L_VOID TerminateStore(HWND hDlg) { // Kill timer KillTimer(hDlg, IDT_MY_TIMER); if (L_DicomIsConnected(ghSTRDicomNet)) { if (L_DicomIsAssociated(ghSTRDicomNet)) { L_DicomSendAbort(ghSTRDicomNet, PDU_ABORT_SOURCE_USER, 0); } // Close the connection CloseConnection(hDlg, ghSTRDicomNet); } OnStatus(hDlg, STR_PROCESS_TERMINATED, 0); // Close progress dialog EndDialog(hDlg, 0); return; } L_VOID CloseConnection(HWND hDlg, HDICOMNET hNet) { // Close the connection L_DicomClose(hNet); // Status OnStatus(hDlg, STR_CONNECTION_CLOSED, 0); } // Get the current file name L_VOID OnProgressFiles(HWND hDlg, L_CHAR* pszFileName) { L_CHAR szStatus[5000]; if (!pszFileName) return; SetDlgItemText(hDlg, IDC_STAT_FILENAME, pszFileName); // Get the text in the status edit box GetDlgItemText(GetParent(hDlg), IDC_EDIT_STATUS, szStatus, sizeof(szStatus)); wsprintf(szStatus, "%s%s\r\n", szStatus, pszFileName); // Show the status in the staus edit box SetDlgItemText(GetParent(hDlg), IDC_EDIT_STATUS, szStatus); }