some questions about loading the CAPE-OPEN dll

some questions about loading the CAPE-OPEN dll

Postby bcbooo » 09 January 2013, 03:27

Recently I write some code to load the CAPE-OPEN dll files, I have no problem to get the interface of "IDispatch", "ICapeIdentification" and "ICapeUnit", and the functions in ICapeIdentification can be called very well. But for some specific CAPE-OPEN dll, when I use functions in ICapeUnit, It's always terminate with error, the warning message is:

****************************************************
Microsoft Visual C++ Debug Library

Debug Error!
Program: f:\c works\cd\debug\dc.exe

This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.
******************************************************

My source code is:
*******************
CoInitialize(NULL);
CLSID clsid;
CLSIDFromProgID(OLESTR("COCO_COUS.Compressor.1"),&clsid);
//after intalled COCO,you could find "COCO_COUS.Compressor.1" from registry

CComPtr<IDispatch> pGetRes;
CComPtr<ICapeIdentification> iCapeIdenti;
pGetRes.CoCreateInstance(clsid);
CComPtr<ICapeUnit> iCapeUnit;

//the following get the interface of ICapeUnit, for most CAPE-OPEN dlls, It has no problem, but when call the functions in ICapeUnit, it will terminate.
HRESULT hr=pGetRes->QueryInterface(__uuidof(ICapeUnit),(LPVOID*)&iCapeUnit);
if(SUCCEEDED(hr)) AfxMessageBox(_T("QueryInterface ICapeUnit Succeeded"));
else return;

//the following get the interface of ICapeIdentification
hr=pGetRes->QueryInterface(__uuidof(ICapeIdentification),(LPVOID*)& iCapeIdenti);
if(SUCCEEDED(hr)) AfxMessageBox(_T("QueryInterface ICapeIdentification Succeeded"));
else return;

//the following get the description of component, use the ICapeIdentification interface, it's always right
_bstr_t abc= iCapeIdenti->GetComponentDescription();
CString des;
des=(LPCSTR)abc;
AfxMessageBox(_T("the component's description is ")+des);

//the following get the ValStatus of component, use the ICapeUnit interface, for some components it's always wrong, I don't know why.
CapeValidationStatus cvs=iCapeUnit->GetValStatus();
CString cv;
cv.Format(_T(" CapeValidationStatus is %d"),cvs);
AfxMessageBox(cv);

//the following get the ports, if "iCapeUnit->GetValStatus()" is succeeded, this one will be succeed.
LPDISPATCH ld=iCapeUnit->Getports();
CComPtr<ICapeCollection> iCapeCollection;
hr=ld->QueryInterface(__uuidof(ICapeCollection),(LPVOID*)&iCapeCollection);
if(SUCCEEDED(hr)) AfxMessageBox(_T("QueryInterface ICapeCollection Succeeded"));
else return;

//show the count of ports
CString pc;
pc.Format(_T("the count of ports is %d"),iCapeCollection->Count());
AfxMessageBox(pc);

CoUninitialize();
*******************
for most CAPE-OPEN dlls, the above code will runs very good,for example the "CPPMixerSplitterexample.dll", but others like "COCOCOUS.dll","COCO_COUS.HeatExchanger.1","COCO_COUS.HeaterCooler.1","COCO_COUS.CSTR.1" from COCO is always terminate. But I tried the "COCOCOUS.dll","COCO_COUS.HeatExchanger.1","COCO_COUS.HeaterCooler.1","COCO_COUS.CSTR.1" in Aspen Plus V7.2, aspen runs very well, so I suspect whether my code has some problem ?

On the other hand, I can't use "Initialize()" function in ICapeUnit, and I can't use "ICapeUnitCollection" too, my tlb file is "CAPE-OPENv1-1-0.tlb", I don't find the reason.
bcbooo
 
Posts: 66
Joined: 22 November 2012, 06:41
Location: China

Re: some questions about loading the CAPE-OPEN dll

Postby jasper » 09 January 2013, 08:26

The unit operation returns an ECapeUnknownHR because you are not calling ICapeUtillities::Initialize before calling functionality on the unit. Note that you should also check if IPersistStreamInit is implemented, and if so, call its InitNew function before Initialize. If any loading is to be done, IPersistStream(Init)'s Load should be called instead of InitNew, and before Initialize.

the COMPTR generated this code for you

inline CapeValidationStatus ICapeUnit::GetValStatus ( ) {
CapeValidationStatus _result;
HRESULT _hr = get_ValStatus(&_result);
if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
return _result;
}

The error code was known (but not to you) and translated into an exception. Either call the raw function (giving you the error code) or catch the exception to find out what is going on. As the exception code is of type ECapeUnknownHR, you can query for ECapeUnkown, which derives from ECapeUser (all CAPE-OPEN error codes, except ECapeRoot, do), which will give you a textual error message. For example:

try
{CapeValidationStatus cvs=iCapeUnit->GetValStatus();
CString cv;
cv.Format(_T(" CapeValidationStatus is %d"),cvs);
AfxMessageBox(cv);
}
catch( _com_error &e )
{if (e.Error()==ECapeUnknownHR) //this should of course do a better check, see for example CO_Error in the CAPE-OPEN example projects
{CComPtr<ECapeUser> eCapeUser;
hr=pGetRes->QueryInterface(__uuidof(ECapeUser),(LPVOID*)& eCapeUser);
if(SUCCEEDED(hr))
{abc=eCapeUser->Getdescription();
des=(LPCSTR)abc;
AfxMessageBox(_T("the problem is: ")+des);
}
}
}

results

The problem is: Initialize not called

but after that it will crash as getting the port collection fails for the same reason and has no error check. Ergo: always check the errors returned from CAPE-OPEN operations. Hopefully with that you will get a decent error description via ECapeUser, or a standard COM error code (e.g. E_OUTOFMEMORY).

Personally I prefer calling the raw functions and always checking the error code. E.g.

hr=iCapeUnit->get_ValStatus(&cvs);'
if (FAILED(hr)) / if (SUCCEEDED(hr))

seems simpler than a try/catch around everything.

Hope that helps.
User avatar
jasper
 
Posts: 1128
Joined: 24 October 2012, 15:33
Location: Spain

Re: some questions about loading the CAPE-OPEN dll

Postby bcbooo » 09 January 2013, 08:48

jasper wrote:The unit operation returns an ECapeUnknownHR because you are not calling ICapeUtillities::Initialize before calling functionality on the unit. Note that you should also check if IPersistStreamInit is implemented, and if so, call its InitNew function before Initialize. If any loading is to be done, IPersistStream(Init)'s Load should be called instead of InitNew, and before Initialize.

the COMPTR generated this code for you

inline CapeValidationStatus ICapeUnit::GetValStatus ( ) {
CapeValidationStatus _result;
HRESULT _hr = get_ValStatus(&_result);
if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
return _result;
}

The error code was known (but not to you) and translated into an exception. Either call the raw function (giving you the error code) or catch the exception to find out what is going on. As the exception code is of type ECapeUnknownHR, you can query for ECapeUnkown, which derives from ECapeUser (all CAPE-OPEN error codes, except ECapeRoot, do), which will give you a textual error message. For example:

try
{CapeValidationStatus cvs=iCapeUnit->GetValStatus();
CString cv;
cv.Format(_T(" CapeValidationStatus is %d"),cvs);
AfxMessageBox(cv);
}
catch( _com_error &e )
{if (e.Error()==ECapeUnknownHR) //this should of course do a better check, see for example CO_Error in the CAPE-OPEN example projects
{CComPtr<ECapeUser> eCapeUser;
hr=pGetRes->QueryInterface(__uuidof(ECapeUser),(LPVOID*)& eCapeUser);
if(SUCCEEDED(hr))
{abc=eCapeUser->Getdescription();
des=(LPCSTR)abc;
AfxMessageBox(_T("the problem is: ")+des);
}
}
}

results

The problem is: Initialize not called

but after that it will crash as getting the port collection fails for the same reason and has no error check. Ergo: always check the errors returned from CAPE-OPEN operations. Hopefully with that you will get a decent error description via ECapeUser, or a standard COM error code (e.g. E_OUTOFMEMORY).

Personally I prefer calling the raw functions and always checking the error code. E.g.

hr=iCapeUnit->get_ValStatus(&cvs);'
if (FAILED(hr)) / if (SUCCEEDED(hr))

seems simpler than a try/catch around everything.

Hope that helps.


Thank you jasper, I will have a try again.
bcbooo
 
Posts: 66
Joined: 22 November 2012, 06:41
Location: China


Return to Unit Operations

Who is online

Users browsing this forum: No registered users and 1 guest

cron