最近在研究DCMTK,目的是通过输入患者ID或者姓名,获取到该患者的序列并传输到本地。
目前已经安装好DCMTK库,使用ConquestDICOMServer构建了服务端,去查询信息时用到了 ASC_addPresentationContext(params, presentationContextID,
UID_FINDStudyRootQueryRetrieveInformationModel,
,但是输出的结果在服务端打印如下:
[CONQUESTSRV1] Calling Application Title : "CONQUESTSRV1 "
[CONQUESTSRV1] Called Application Title : "CONQUESTSRV1 "
[CONQUESTSRV1] Application Context : "1.2.840.10008.3.1.1.1", PDU length: 16384
[CONQUESTSRV1] Presentation Context 0 "1.2.840.10008.5.1.4.1.2.2.1" 1
[CONQUESTSRV1] **(StudyRootQuery) search level: **
[CONQUESTSRV1] C-Find (StudyRoot) located 0 records
CONQUESTSRV1 search level:
[CONQUESTSRV1] C-Find (StudyRoot) located 0 records
问题点:1. search level 没有值;
2.应用上下文,描述上下文是否添加正确;
3.服务端和客户端的编码方案是否存在问题。
主要代码附:
OFCmdUnsignedInt maxXferSyntaxes = OFstatic_cast(OFCmdUnsignedInt, (DIM_OF(transferSyntaxes)));
T_ASC_Network *net;
T_ASC_Parameters *params;
DIC_NODENAME localHost;
DIC_NODENAME peerHost;
T_ASC_Association *assoc;
OFString temp_str;
WSAData winSockData;
/* we need at least version 1.1 */
WORD winSockVersionNeeded = MAKEWORD( 1, 1 );
WSAStartup(winSockVersionNeeded, &winSockData);
if (!dcmDataDict.isDictionaryLoaded())
{
printf("No data dictionary loaded, check environment variable\n");
}
/* initialize network, i.e. create an instance of T_ASC_Network*. */
OFCondition cond = ASC_initializeNetwork(NET_REQUESTOR, 0, 30, &net);
if (cond.bad())
{
return DCMLIB_E_UNEXPECTED;
}
/* initialize asscociation parameters, i.e. create an instance of T_ASC_Parameters*. */
cond = ASC_createAssociationParameters(¶ms, ASC_DEFAULTMAXPDU);
if (cond.bad())
{
return DCMLIB_E_UNEXPECTED;
}
/* sets this application's title and the called application's title in the params */
/* structure. The default values to be set here are "STORESCU" and "ANY-SCP". */
ASC_setAPTitles(params, opt_ourTitle.c_str(), opt_peerTitle.c_str(), NULL);
/* Set the transport layer type (type of network connection) in the params */
/* strucutre. The default is an insecure connection; where OpenSSL is */
/* available the user is able to request an encrypted,secure connection. */
cond = ASC_setTransportLayerType(params, OFFalse);
if (cond.bad())
{
return DCMLIB_E_UNEXPECTED;
}
/* Figure out the presentation addresses and copy the */
/* corresponding values into the association parameters.*/
gethostname(localHost, sizeof(localHost) - 1);
sprintf_s(peerHost, "%s:%d", opt_peer.c_str(), OFstatic_cast(int, opt_port));
ASC_setPresentationAddresses(params, localHost, peerHost);
/* Set the presentation contexts which will be negotiated */
/* when the network connection will be established */
int presentationContextID = 1; /* odd byte value 1, 3, 5, .. 255 */
for (unsigned long ii=0; ii<1; ii++)
{
cond = ASC_addPresentationContext(params, presentationContextID,
UID_FINDStudyRootQueryRetrieveInformationModel,
transferSyntaxes, OFstatic_cast(int,1));
presentationContextID += 2;
if (cond.bad())
{
return DCMLIB_E_UNEXPECTED;
}
}
/* create association, i.e. try to establish a network connection to another */
/* DICOM application. This call creates an instance of T_ASC_Association*. */
cond = ASC_requestAssociation(net, params, &assoc);
if (cond.bad())
{
if (cond == DUL_ASSOCIATIONREJECTED)
{
T_ASC_RejectParameters rej;
ASC_getRejectParameters(params, &rej);
}
ASC_destroyAssociation(&assoc);
ASC_dropNetwork(&net);
WSACleanup();
return DCMLIB_E_SERVER_NOT_RESPONE;
}
/* count the presentation contexts which have been accepted by the SCP */
/* If there are none, finish the execution */
if (ASC_countAcceptedPresentationContexts(params) == 0)
{
ASC_destroyAssociation(&assoc);
ASC_dropNetwork(&net);
WSACleanup();
return DCMLIB_E_SERVER_NOT_RESPONE;
}
/* do the real work, i.e. send a number of C-ECHO-RQ messages to the DICOM application */
/* this application is connected with and handle corresponding C-ECHO-RSP messages. */
// cond = cecho(assoc, 1);
T_ASC_PresentationContextID presID;
T_DIMSE_C_FindRQ req;
T_DIMSE_C_FindRSP rsp;
DcmFileFormat dcmff;
const char* abstractSyntax = UID_FINDStudyRootQueryRetrieveInformationModel;
presID = ASC_findAcceptedPresentationContextID(assoc, abstractSyntax);
if (presID == 0)
{
printf("No presentation context\n");
return -8;
}
//8)发起C-FIND请求
//8.1)准备C-FIND-RQ message
bzero(OFreinterpret_cast(char*, &req), sizeof(req));//内存初始化为空;
strcpy_s(req.AffectedSOPClassUID, abstractSyntax);
req.DataSetType = DIMSE_DATASET_PRESENT;
req.Priority = DIMSE_PRIORITY_LOW;
//设置要查询的信息为空时,待会儿查询结果中会返回
DcmDataset* dataset = new DcmDataset();
InsertQueryItems(dataset, "","*8");
ZSCFindCallback zsCallback;
DcmFindSCUCallback* callback = &zsCallback;
callback->setAssociation(assoc);
callback->setPresentationContextID(presID);
/* as long as no error occured and the counter does not equal 0 */
cond = EC_Normal;
int rescout = 1;
while (cond.good())
{
DcmDataset *statusDetail = NULL;
/* complete preparation of C-FIND-RQ message */
req.MessageID = assoc->nextMsgID++;
/* finally conduct transmission of data */
cond = DIMSE_findUser(assoc, presID, &req, dataset,
rescout,progressCallback, callback, DIMSE_BLOCKING, 30,
&rsp, &statusDetail);
//设置了查询采用阻塞模式,DIMSE_BLOCKING
//设置连接超时为50
/*
*添加异常判别
*
*/
//cond = EC_EndOfStream;//假设异常,返回
}
/* tear down association, i.e. terminate network connection to SCP */
if (cond == EC_Normal)
{
/* release association */
cond = ASC_releaseAssociation(assoc);
if (cond.bad())
{
ASC_destroyAssociation(&assoc);
ASC_dropNetwork(&net);
WSACleanup();
return DCMLIB_E_FAILED_TO_EXEC;
}
}
else if (cond == DUL_PEERREQUESTEDRELEASE)
{
cond = ASC_abortAssociation(assoc);
if (cond.bad())
{
ASC_destroyAssociation(&assoc);
ASC_dropNetwork(&net);
WSACleanup();
return DCMLIB_E_FAILED_TO_EXEC;
}
}
else if (cond == DUL_PEERABORTEDASSOCIATION)
{
}
else
{
cond = ASC_abortAssociation(assoc);
if (cond.bad())
{
ASC_destroyAssociation(&assoc);
ASC_dropNetwork(&net);
WSACleanup();
return DCMLIB_E_FAILED_TO_EXEC;
}
}
/* destroy the association, i.e. free memory of T_ASC_Association* structure. This */
/* call is the counterpart of ASC_requestAssociation(...) which was called above. */
cond = ASC_destroyAssociation(&assoc);
if (cond.bad())
{
return DCMLIB_E_FAILED_TO_EXEC;
}
/* drop the network, i.e. free memory of T_ASC_Network* structure. This call */
/* is the counterpart of ASC_initializeNetwork(...) which was called above. */
cond = ASC_dropNetwork(&net);
if (cond.bad())
{
return DCMLIB_E_ACCESS_DENIED;
}
WSACleanup();
return DCMLIB_S_OK;