//头文件
#ifndef DICOMCFINDSCU_H
#define DICOMCFINDSCU_H
#include "dcmtk/config/osconfig.h"
#include "dcmtk/ofstd/ofcond.h" /* for class OFCondition */
#include "dcmtk/dcmdata/dcxfer.h" /* for E_TransferSyntax */
#include "dcmtk/dcmnet/dimse.h" /* for T_DIMSE_BlockingMode */
#include <string>
class DcmDataset;
class DcmTransportLayer;
class OFConsoleApplication;
struct T_ASC_Association;
struct T_ASC_Parameters;
struct T_DIMSE_C_FindRQ;
struct T_DIMSE_C_FindRSP;
class DicomCfindScuCallback
{
public:
DicomCfindScuCallback();
virtual ~DicomCfindScuCallback() {}
virtual void callback(
T_DIMSE_C_FindRQ *request,
int responseCount,
T_DIMSE_C_FindRSP *rsp,
DcmDataset *responseIdentifiers) = 0;
void setAssociation(T_ASC_Association *assoc);
void setPresentationContextID(T_ASC_PresentationContextID presId);
protected:
T_ASC_Association *assoc_;
T_ASC_PresentationContextID presId_;
private:
DicomCfindScuCallback(const DicomCfindScuCallback& other);
DicomCfindScuCallback& operator=(const DicomCfindScuCallback& other);
};
//默认回调
class DicomCfindScuDefaultCallback:
public DicomCfindScuCallback
{
public:
DicomCfindScuDefaultCallback(int cancelAfterNResponses);
virtual void callback(
T_DIMSE_C_FindRQ *request,
int responseCount,
T_DIMSE_C_FindRSP *rsp,
DcmDataset *responseIdentifiers);
protected:
int cancelAfterNResponses_;
};
struct tag_findkey
{
std::string studydate;
std::string studytime;
std::string paitientId;
std::string paitientname;
std::string accessionNumber;
std::string birthdate;
std::string studyid;
std::string studyInstanceUid;
std::string studyDes;
std::string refphName;
std::string sericeNumber;
std::string sericeUid;
std::string instanceNumber;
std::string instanceUid;
std::string reqId;
std::string ppsid;
std::string studyinMod;
std::string sericeMod;
std::string ppsdate;
std::string ppstime;
std::string ql;
//net
std::string aet_;
std::string ip_;
int port_;
std::string aeted_;
bool secureConnection;
unsigned short maxReceivePDULength;
unsigned short acse_timeout;
//回调指针
DicomCfindScuCallback *ccallback;
tag_findkey()
{
maxReceivePDULength=16383;
secureConnection=false;
acse_timeout=10;
}
};
class DicomCfindScu
{
public:
DicomCfindScu();
~DicomCfindScu();
OFCondition initializeNetwork(int acse_timeout);
OFCondition setTransportLayer(DcmTransportLayer *tLayer);
OFCondition dropNetwork();
OFCondition addPresentationContext(
T_ASC_Parameters *params,
const char *abstractSyntax,
E_TransferSyntax preferredTransferSyntax);
bool find();
bool cfind();
void SetParamter(tag_findkey &findkey);
void setFindType(int findtype_);
private:
tag_findkey findkey_;
T_ASC_Network *net_;
int findtype;
};
#endif
//源文件
#include "winsock2.h"
#include "stdafx.h"
#include "DicomCfindScu.h"
#include "dcmtk/ofstd/ofstdinc.h"
#include "dcmtk/dcmnet/diutil.h"
#include "dcmtk/dcmdata/dcfilefo.h"
#include "dcmtk/dcmdata/dcdicent.h"
#include "dcmtk/dcmdata/dcdict.h"
#include "dcmtk/dcmdata/dcpath.h"
#include "dcmtk/ofstd/ofconapp.h"
#include "dcmtk/dcmdata/dcdeftag.h"
#include "../pacslog.h"
static void DicomCfindScuprogress(
void *callbackData,
T_DIMSE_C_FindRQ *request,
int responseCount,
T_DIMSE_C_FindRSP *rsp,
DcmDataset *responseIdentifiers)
{
DicomCfindScuCallback *callback = OFreinterpret_cast(DicomCfindScuCallback *, callbackData);
if (callback) callback->callback(request, responseCount, rsp, responseIdentifiers);
}
DicomCfindScuCallback::DicomCfindScuCallback()
: assoc_(NULL)
, presId_(0)
{
}
void DicomCfindScuCallback::setAssociation(T_ASC_Association *assoc)
{
assoc_ = assoc;
}
void DicomCfindScuCallback::setPresentationContextID(T_ASC_PresentationContextID presId)
{
presId_ = presId;
}
DicomCfindScuDefaultCallback::DicomCfindScuDefaultCallback(int cancelAfterNResponses)
:DicomCfindScuCallback(),
cancelAfterNResponses_(cancelAfterNResponses)
{
}
void DicomCfindScuDefaultCallback::callback(
T_DIMSE_C_FindRQ *request,
int responseCount,
T_DIMSE_C_FindRSP *rsp,
DcmDataset *responseIdentifiers)
{
OFString temp_str;
DCMNET_INFO("Received Find Response " << responseCount);
DCMNET_DEBUG(DIMSE_dumpMessage(temp_str, *rsp, DIMSE_INCOMING));
DCMNET_DEBUG("Response Identifiers:" << OFendl << DcmObject::PrintHelper(*responseIdentifiers));
if (cancelAfterNResponses_ == responseCount)
{
DCMNET_INFO("Sending Cancel Request (MsgID " << request->MessageID
<< ", PresID " << OFstatic_cast(unsigned int, presId_) << ")");
OFCondition cond = DIMSE_sendCancelRequest(assoc_, presId_, request->MessageID);
if (cond.bad())
{
OFString temp_str;
DCMNET_ERROR("Cancel Request Failed: " << DimseCondition::dump(temp_str, cond));
}
}
}
//=====================================================
DicomCfindScu::DicomCfindScu()
:net_(0)
,findtype(0)
{
}
DicomCfindScu::~DicomCfindScu()
{
dropNetwork();
delete findkey_.ccallback;
}
OFCondition DicomCfindScu::initializeNetwork(int acse_timeout)
{
return ASC_initializeNetwork(NET_REQUESTOR, 0, acse_timeout, &net_);
}
OFCondition DicomCfindScu::setTransportLayer(DcmTransportLayer *tLayer)
{
return ASC_setTransportLayer(net_, tLayer, 0);
}
OFCondition DicomCfindScu::dropNetwork()
{
if (net_) return ASC_dropNetwork(&net_); else return EC_Normal;
}
OFCondition DicomCfindScu::addPresentationContext(
T_ASC_Parameters *params,
const char *abstractSyntax,
E_TransferSyntax preferredTransferSyntax)
{
const char* transferSyntaxes[] = { NULL, NULL, NULL, NULL };
int numTransferSyntaxes = 0;
switch (preferredTransferSyntax) {
case EXS_LittleEndianImplicit:
transferSyntaxes[0] = UID_LittleEndianImplicitTransferSyntax;
numTransferSyntaxes = 1;
break;
case EXS_LittleEndianExplicit:
transferSyntaxes[0] = UID_LittleEndianExplicitTransferSyntax;
transferSyntaxes[1] = UID_BigEndianExplicitTransferSyntax;
transferSyntaxes[2] = UID_LittleEndianImplicitTransferSyntax;
numTransferSyntaxes = 3;
break;
case EXS_BigEndianExplicit:
transferSyntaxes[0] = UID_BigEndianExplicitTransferSyntax;
transferSyntaxes[1] = UID_LittleEndianExplicitTransferSyntax;
transferSyntaxes[2] = UID_LittleEndianImplicitTransferSyntax;
numTransferSyntaxes = 3;
break;
default:
if (gLocalByteOrder == EBO_LittleEndian) /* defined in dcxfer.h */
{
transferSyntaxes[0] = UID_LittleEndianExplicitTransferSyntax;
transferSyntaxes[1] = UID_BigEndianExplicitTransferSyntax;
} else {
transferSyntaxes[0] = UID_BigEndianExplicitTransferSyntax;
transferSyntaxes[1] = UID_LittleEndianExplicitTransferSyntax;
}
transferSyntaxes[2] = UID_LittleEndianImplicitTransferSyntax;
numTransferSyntaxes = 3;
break;
}
return ASC_addPresentationContext(
params, 1, abstractSyntax,
transferSyntaxes, numTransferSyntaxes);
}
bool DicomCfindScu::cfind()
{
T_ASC_Association *assoc = NULL;
T_ASC_Parameters *params = NULL;
DIC_NODENAME localHost;
DIC_NODENAME peerHost;
OFString temp_str;
OFCondition cond=EC_Normal;
const char *abstractSyntax=UID_FINDPatientRootQueryRetrieveInformationModel;
OFBool abortAssociation=OFTrue;
//==============================
T_ASC_PresentationContextID presId;
T_DIMSE_C_FindRQ req;
T_DIMSE_C_FindRSP rsp;
int repeatCount=1;
T_DIMSE_BlockingMode opt_blockMode = DIMSE_BLOCKING;
#ifdef HAVE_WINSOCK_H
WSAData winSockData;
/* we need at least version 1.1 */
WORD winSockVersionNeeded = MAKEWORD( 1, 1 );
WSAStartup(winSockVersionNeeded, &winSockData);
#endif
//1 初始化网络
cond=initializeNetwork(findkey_.acse_timeout);
if (cond.bad()) {
DICOM_ERROR(DimseCondition::dump(temp_str, cond));
return false;
}
//2 创建关联参数
cond=ASC_createAssociationParameters(¶ms,findkey_.maxReceivePDULength);
if (cond.bad()){
DICOM_ERROR(DimseCondition::dump(temp_str, cond));
return false;
}
//3 设置aet
ASC_setAPTitles(params, findkey_.aet_.c_str(), findkey_.aeted_.c_str(), NULL);
//4 设置安全存
cond = ASC_setTransportLayerType(params, findkey_.secureConnection);
if (cond.bad()) return false;
//5 添加演示地址
gethostname(localHost, sizeof(localHost) - 1);
sprintf(peerHost, "%s:%d", findkey_.ip_.c_str(), findkey_.port_);
ASC_setPresentationAddresses(params, localHost, peerHost);
//6 添加演示上下文
cond = addPresentationContext(params, abstractSyntax,EXS_LittleEndianExplicit);
if (cond.bad()) return false;
DICOM_INFO("Request Parameters:" << OFendl << ASC_dumpParameters(temp_str, params, ASC_ASSOC_RQ));
DCMNET_INFO("Requesting Association");
// 7请求关联
cond = ASC_requestAssociation(net_, params, &assoc);
if (cond.bad()) {
if (cond == DUL_ASSOCIATIONREJECTED) {
T_ASC_RejectParameters rej;
ASC_getRejectParameters(params, &rej);
DICOM_ERROR("Association Rejected:" << OFendl << ASC_printRejectParameters(temp_str, &rej));
return false;
} else {
DICOM_ERROR("Association Request Failed: " << DimseCondition::dump(temp_str, cond));
return false;
}
}
DICOM_INFO("Association Parameters Negotiated:" << OFendl << ASC_dumpParameters(temp_str, params, ASC_ASSOC_AC));
//8关联上下文数量
if (ASC_countAcceptedPresentationContexts(params) == 0) {
DICOM_ERROR("No Acceptable Presentation Contexts");
return false;
}
//9查找
presId = ASC_findAcceptedPresentationContextID(assoc, abstractSyntax);
if (presId == 0) {
DICOM_ERROR("No presentation context");
return false;
}
/* prepare C-FIND-RQ message */
bzero(OFreinterpret_cast(char*, &req), sizeof(req));
strcpy(req.AffectedSOPClassUID, abstractSyntax);
req.DataSetType = DIMSE_DATASET_PRESENT;
req.Priority = DIMSE_PRIORITY_LOW;
/* prepare the callback data */
findkey_.ccallback->setAssociation(assoc);
findkey_.ccallback->setPresentationContextID(presId);
int n = repeatCount;
cond=EC_Normal;
DcmDataset dset;
if (findtype==0){
dset.putAndInsertString(DCM_PatientID,findkey_.paitientId.c_str());
dset.putAndInsertString(DCM_PatientName,findkey_.paitientname.c_str());
dset.putAndInsertString(DCM_PatientBirthDate,findkey_.birthdate.c_str());
dset.putAndInsertString(DCM_StudyDate,findkey_.studydate.c_str());
dset.putAndInsertString(DCM_StudyTime,findkey_.studytime.c_str());
dset.putAndInsertString(DCM_AccessionNumber,findkey_.accessionNumber.c_str());
dset.putAndInsertString(DCM_StudyID,findkey_.studyid.c_str());
dset.putAndInsertString(DCM_StudyInstanceUID,findkey_.studyInstanceUid.c_str());
dset.putAndInsertString(DCM_StudyDescription,findkey_.studyDes.c_str());
dset.insertEmptyElement(DCM_ModalitiesInStudy);
dset.putAndInsertString(DCM_ReferringPhysicianName,findkey_.paitientId.c_str());
dset.putAndInsertString(DCM_NumberOfStudyRelatedInstances,"");
dset.putAndInsertString(DCM_SeriesNumber,findkey_.sericeNumber.c_str());
dset.putAndInsertString(DCM_SeriesInstanceUID,findkey_.sericeUid.c_str());
dset.putAndInsertString(DCM_InstanceNumber,findkey_.instanceNumber.c_str());
dset.putAndInsertString(DCM_SOPInstanceUID,findkey_.instanceUid.c_str());
dset.putAndInsertString(DCM_RequestedProcedureID,findkey_.reqId.c_str());
dset.putAndInsertString(DCM_ScheduledProcedureStepID ,findkey_.reqId.c_str());
dset.putAndInsertString(DCM_RequestedProcedureID,findkey_.ppsid.c_str());
dset.putAndInsertString(DCM_ModalitiesInStudy,findkey_.studyinMod.c_str());
dset.putAndInsertString(DCM_Modality,findkey_.sericeMod.c_str());
dset.putAndInsertString(DCM_PerformedProcedureStepStartDate,findkey_.ppsdate.c_str());
dset.putAndInsertString(DCM_PerformedProcedureStepStartTime,findkey_.ppstime.c_str());
dset.putAndInsertString(DCM_QueryRetrieveLevel,findkey_.ql.c_str());
}
else if (findtype==1){
dset.putAndInsertString(DCM_StudyInstanceUID,findkey_.studyInstanceUid.c_str());
dset.putAndInsertString(DCM_QueryRetrieveLevel,findkey_.ql.c_str());
dset.insertEmptyElement(DCM_Modality);
dset.insertEmptyElement(DCM_SeriesNumber);
dset.insertEmptyElement(DCM_SeriesDescription);
dset.insertEmptyElement(DCM_SeriesInstanceUID);
dset.insertEmptyElement(DCM_NumberOfSeriesRelatedInstances);
}
//DICOM_INFO("查找条件:" << OFendl << DcmObject::PrintHelper(dset));
while (cond.good() && n--)
{
DcmDataset *statusDetail = NULL;
req.MessageID = assoc->nextMsgID++;
if (DCM_dcmnetLogger.isEnabledFor(OFLogger::DEBUG_LOG_LEVEL))
{
DICOM_INFO("Sending Find Request");
DICOM_DEBUG(DIMSE_dumpMessage(temp_str, req, DIMSE_OUTGOING, NULL, presId));
} else {
DICOM_INFO("Sending Find Request (MsgID " << req.MessageID << ")");
}
DICOM_INFO("Request Identifiers:" << OFendl << DcmObject::PrintHelper(dset));
/* finally conduct transmission of data */
cond = DIMSE_findUser(assoc, presId, &req, &dset,
DicomCfindScuprogress, findkey_.ccallback, opt_blockMode, findkey_.acse_timeout,
&rsp, &statusDetail);
if (statusDetail != NULL) {
DICOM_DEBUG("Status Detail:" << OFendl << DcmObject::PrintHelper(*statusDetail));
delete statusDetail;
}
}
//10释放关联
if (cond == EC_Normal)
{
if (abortAssociation) {
DICOM_INFO("Aborting Association");
cond = ASC_abortAssociation(assoc);
if (cond.bad()) {
DICOM_ERROR("Association Abort Failed: " << DimseCondition::dump(temp_str, cond));
return false;
}
} else {
/* release association */
DICOM_INFO("Releasing Association");
cond = ASC_releaseAssociation(assoc);
if (cond.bad())
{
DCMNET_ERROR("Association Release Failed: " << DimseCondition::dump(temp_str, cond));
return false;
}
}
}
else if (cond == DUL_PEERREQUESTEDRELEASE)
{
DICOM_ERROR("Protocol Error: Peer requested release (Aborting)");
DICOM_INFO("Aborting Association");
cond = ASC_abortAssociation(assoc);
if (cond.bad()) {
DICOM_ERROR("Association Abort Failed: " << DimseCondition::dump(temp_str, cond));
return false;
}
}
else if (cond == DUL_PEERABORTEDASSOCIATION)
{
DICOM_INFO("Peer Aborted Association");
}
else
{
DICOM_ERROR("Find SCU Failed: " << DimseCondition::dump(temp_str, cond));
DICOM_INFO("Aborting Association");
cond = ASC_abortAssociation(assoc);
if (cond.bad()) {
DCMNET_ERROR("Association Abort Failed: " << DimseCondition::dump(temp_str, cond));
return false;
}
}
//11 删除关联
cond = ASC_destroyAssociation(&assoc);
if (cond.bad())
DICOM_ERROR(DimseCondition::dump(temp_str, cond));
//12 删除网络
dropNetwork();
return true;
}
void DicomCfindScu::SetParamter(tag_findkey &findkey)
{
findkey_=findkey;
}
bool DicomCfindScu::find()
{
bool isok=false;
isok=cfind();
delete this;
return isok;
}
void DicomCfindScu::setFindType(int findtype_)
{
findtype=findtype_;
}
//dicom协议交流群:107534874