01-22-2014 06:12 AM
Hi,
Windows7, PCI-GPIB, NI-488.2 Version 3.1.1, Visual Studio 2010 C++ Application.
Randomly between 10 minuntes and 4 hours I get the error "pure virtual function call"
With the debbuger attached to the process in error I identified NI4882.dll as the source of the error.
Then I deinstalled NI-488.2 Version 3.1.1 and installed NI488.2 July 2000. Then my application runs without any error!
I tried to attach the source files which represents the interface between my application and the NI-4882 driver but it did not work for the C++ file.
Any help appreciated.
Best Regards
Walter
01-24-2014 07:00 AM - edited 01-24-2014 07:00 AM
Hello Walter,
I could not find anything related to the ni4882.dll and a pure virtual function call but does this article might help understand what is happening:
http://forums.ni.com/t5/NI-TestStand/Pure-Virtual-Function-Call-Error/td-p/101802
Did you try installing the recent NI 488.2 3.1.2 driver (http://www.ni.com/download/labview-real-time-module-2012/3080/en/ )?
Could you post your C++ source code?
Best regards
AndGar
01-27-2014 03:18 AM
Hi AndGar,
After the first time when I got the error "pure virtual function call" I installed with _set_purecall_handler (myHandler) my own handler and this handler creates a minidump. When I forced a pure virtual call within my application then my own handler was called and a minidump was written.
When I got the error "pure virtual function call" from the ni4882.dll, then the original "pure virtual function call" Message Box was displayed. And when I attached the debugger, the ni4882.dll was the bottom module of the callstack.
Here my code (I had to delete most of the comments and split to 2 messages because of the limits of this forum)
1. The Interface declaration
#ifndef MC_IGPIB_H #define MC_IGPIB_H #include "Interfaces/_Interface.h" namespace MC { // Default for one GPIB const Tstring kGPIB = _T("GPIB0"); // use GPIB1, GPIB2 up to GPIB9 for multiple cards. struct SGpibDevInfo { Int mGpibAdr; bool mRemote; HANDLE mSRQEvent; Tstring mVendorName; Tstring mModelName; char mSerialPoll; Int mIbsta1; Int mIbsta2; Int mIberr; Int mIbcntl; }; // Get the interface IGpib with MC::IApplication::AppObject (kGPIB). struct IGpib : public IInterface { virtual bool Reset() = 0; virtual Int Open(UShort adr, ULong timeoutMs) = 0; virtual bool Close(Int ud) = 0; virtual bool SetTimeout(Int ud, ULong timeoutMs) = 0; virtual ULong Timeout() = 0; virtual bool EnableSRQ(Int ud, HANDLE srqEvent) = 0; virtual bool DisableSRQ(Int ud) = 0; virtual bool Remote(Int ud) = 0; virtual bool Local(Int ud) = 0; virtual char SerialPoll(Int ud) = 0; virtual bool DeviceClear(Int ud) = 0; virtual bool Trigger(Int ud) = 0; virtual bool Send(Int ud, const std::string& data) = 0; virtual bool SendNoEOI (Int ud, const std::string& data) = 0; virtual std::string Enter(Int ud) = 0; virtual std::string EnterNoTimeout(Int ud, ULong timeoutMs) = 0; virtual SGpibDevInfo DeviceInfo(Int ud) = 0; virtual Int ibask(Int ud, Int option, Int* value) = 0; virtual Int ibcmd(Int ud, void* cmdbuf, Long count) = 0; }; } // namespace MC #endif // MC_IGPIB_H
2. The implementation header
#ifndef MC_GPIB_H #define MC_GPIB_H #include "CORE/_Model.h" #include "Interfaces/_IGPIB.h" namespace MC { typedef std::map<Int, SGpibDevInfo> GPIBDevMap; class TGpib : public VModel, public IGpib { public: TGpib (const Tstring& devName = kGPIB); ~TGpib (); bool Reset (); Int Open (UShort adr, ULong timeoutMs); bool Close (Int ud); bool SetTimeout (Int ud, ULong timeoutMs); ULong Timeout (); bool EnableSRQ (Int ud, HANDLE srqEvent); bool DisableSRQ (Int ud); bool Remote (Int ud); bool Local (Int ud); char SerialPoll (Int ud); bool DeviceClear (Int ud); bool Trigger (Int ud); bool Send (Int ud, const std::string& data); bool SendNoEOI (Int ud, const std::string& data); std::string Enter (Int ud); std::string EnterNoTimeout (Int ud, ULong timeoutMs); SGpibDevInfo DeviceInfo (Int ud); Int ibask (Int ud, Int option, Int* value); Int ibcmd (Int ud, void* cmdbuf, long count); private: void GPIBError (Int ud, const Tstring& ctx, bool fatal = false); static Int __stdcall GpibSRQ(Int ud, unsigned long ibsta, unsigned long iberr, unsigned long ibcntl, void* ptr); UInt mBoardID; GPIBDevMap mDevices; ULong mTimeout; }; } // namespace MC #endif // MC_GPIB_H
01-27-2014 03:20 AM
And here part 1 of the implementation:
#include "StdAfx.h" #include "R:\MCLIB\ThirdParty\National\ni4882.h" #include "COMMON/_ErrorHandling.h" #include "COMMON/_Tracing.h" #include "COMMON/_Makros.h" #include "COMMON/_MC_Strings.h" #include "System/_GPIB.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif using namespace std; namespace MC { const char MTA0 = 64; // My Talk Address const Char* ErrorMnemonic[] = {_T("EDVR"), _T("ECIC"), _T("ENOL"), _T("EADR"), _T("EARG"), _T("ESAC"), _T("EABO"), _T("ENEB"), _T("EDMA"), _T("---9"), _T("EOIP"), _T("ECAP"), _T("EFSO"), _T("--13"), _T("EBUS"), _T("ESTB"), _T("ESRQ"), _T("--17"), _T("--18"), _T("--19"), _T("ETAB"), _T("ELCK"), _T("EARM"), _T("EHDL"), _T("ECFG"), _T("--25"), _T("EWIP"), _T("ERST"), _T("EPWR"), _T("OOPS") }; const UShort kErrorMnemonics = sizeof (ErrorMnemonic) / sizeof (ErrorMnemonic[0]); const ULong TimeoutTime[] = { 1, 3, 10, 30, 100, 300, 1000, 3000, 10000, 30000, 100000, 300000, 1000000 }; const UShort kTimeoutTimes = sizeof (TimeoutTime) / sizeof (ULong); Int TimeoutCode (ULong millisec) { if (millisec > 0) { for (UShort i = 0; i < kTimeoutTimes; ++i) { if (millisec <= TimeoutTime[i]) return i + T1ms; } } return TNONE; } class TGpib_TimeoutSetter { public: TGpib_TimeoutSetter (TGpib* drv, Int ud, ULong timeoutTime); ~TGpib_TimeoutSetter (); private: TGpib* mDriver; Int mUd; ULong mOldTimeoutTime; }; TGpib_TimeoutSetter::TGpib_TimeoutSetter (TGpib* drv, Int ud, ULong timeoutTime) { mDriver = drv; mUd = ud; mOldTimeoutTime = mDriver->Timeout (); mDriver->SetTimeout (mUd, timeoutTime); } TGpib_TimeoutSetter::~TGpib_TimeoutSetter () { mDriver->SetTimeout (mUd, mOldTimeoutTime); } struct SDevInfo : public SGpibDevInfo { SDevInfo::SDevInfo () : SGpibDevInfo () { mGpibAdr = -1; mRemote = false; mSRQEvent = NULL; mIbsta1 = 0; mIbsta2 = 0; mIberr = 0; mIbcntl = 0; mVendorName = _T(""); mModelName = _T(""); } }; TGpib::TGpib (const Tstring& devName) : VModel (devName) { mBoardID = devName[4] - _T('0'); SendIFC (mBoardID); ibconfig (mBoardID, IbcAUTOPOLL, 0); ibsre (mBoardID, 1); } TGpib::~TGpib () { ibsre (mBoardID, 0); ibonl (mBoardID, 0); } bool TGpib::Reset () { GPIBDevMap::iterator it = mDevices.begin (); for (; it != mDevices.end (); ++it) Close (it->first); mDevices.clear (); Int stat = ibonl (mBoardID, 0); if ((stat & ERR) != 0) { MCTraceLib (this, eTraceError, TFCTX, _T("Board offline failed")); GPIBError (-1, FCTX, true); return false; } SendIFC (mBoardID); stat = ThreadIbsta (); if ((stat & ERR) != 0) { MCTraceLib (this, eTraceError, TFCTX, _T("send IFC failed")); GPIBError (-1, FCTX, true); return false; } stat = ibconfig (mBoardID, IbcAUTOPOLL, 0); if ((stat & ERR) != 0) { MCTraceLib (this, eTraceError, TFCTX, _T("send IbcAUTOPOLL failed")); GPIBError (-1, FCTX, true); return false; } stat = ibsre (mBoardID, 1); if ((stat & ERR) != 0) { MCTraceLib (this, eTraceError, TFCTX, _T("Set REN failed")); GPIBError (-1, FCTX, true); return false; } return true; }
01-27-2014 03:21 AM
Part 2:
Int TGpib::Open (UShort adr, ULong timeoutMs) { if (mDevices.empty ()) Reset (); Int ud = ibdev (mBoardID, adr, 0, TimeoutCode (timeoutMs), 1, 0); if (ud < 0) { MCTraceLib (this, eTraceError, TFCTX, _T("open device '%d' failed"), adr); GPIBError (-1, FCTX, true); return -1; } SDevInfo devInf; devInf.mGpibAdr = adr; mDevices[ud] = devInf; if (!DeviceClear (ud)) { MCTraceLib (this, eTraceError, TFCTX, _T("no device on address '%d'"), adr); GPIBError (ud, FCTX, true); Close (ud); return -1; } if (Send (ud, "*IDN?")) { Tstring s = String2Tstring (Enter (ud)); StringList l = Split (s, _T(',')); if (l.size () == 4) { mDevices[ud].mVendorName = l[0]; mDevices[ud].mModelName = l[1]; } } else { MCTraceLib (this, eTraceError, TFCTX, _T("no device on address '%d'"), adr); GPIBError (ud, FCTX, true); Close (ud); return -1; } Local (ud); return ud; } bool TGpib::Close (Int ud) { GPIBDevMap::iterator it = mDevices.find (ud); if (it != mDevices.end ()) { Local (ud); Int stat = ibonl (ud, 0); if ((stat & ERR) != 0) { MCTraceLib (this, eTraceError, TFCTX, _T("close device ud = '%d' failed"), ud); GPIBError (ud, FCTX, true); return false; } mDevices.erase (it); return true; } return false; } bool TGpib::SetTimeout (Int ud, ULong timeoutMs) { Int stat = ibtmo (ud, TimeoutCode (timeoutMs)); if ((stat & ERR) != 0) { MCTraceLib (this, eTraceError, TFCTX, _T("set timeout device ud = '%d' failed"), ud); GPIBError (ud, FCTX, true); return false; } return true; } ULong TGpib::Timeout () { return mTimeout; } bool TGpib::EnableSRQ (Int ud, HANDLE srqEvent) { if (srqEvent != INVALID_HANDLE_VALUE) { GPIBDevMap::iterator it = mDevices.find (ud); if (it != mDevices.end ()) { (it->second).mSRQEvent = srqEvent; Int stat = ibnotify (mBoardID, SRQI, GpibSRQ, (void*)this); if ((stat & ERR) != 0) { MCTraceLib (this, eTraceError, TFCTX, _T("on device ud = '%d' failed"), ud); GPIBError (ud, FCTX, true); return false; } MCTraceLib (this, eTraceDebug, TFCTX, _T("(SRQ)on device ud = '%d' success"), ud); return true; } } else { MCTraceLib (this, eTraceError, TFCTX, _T("srqEvent == INVALID_HANDLE_VALUE")); } return false; } bool TGpib::DisableSRQ (Int /*ud*/) { return true; } bool TGpib::Remote (Int ud) { Int adr; ibask (ud, IbaPAD, &adr); adr += 32; // Talk Address = Listen Address + 32 char cmdbuf[] = {MTA0, 0, LLO, UNT, UNL}; cmdbuf[1] = char(adr); Int stat = ibcmd (mBoardID, &cmdbuf, 5); if ((stat & ERR) != 0) { MCTraceLib (this, eTraceError, TFCTX, _T("on device ud = '%d' failed"), ud); GPIBError (ud, FCTX, true); return false; } mDevices[ud].mRemote = true; return true; } bool TGpib::Local (Int ud) { mDevices[ud].mRemote = false; Int stat = ibloc (ud); if ((stat & ERR) != 0) { MCTraceLib (this, eTraceError, TFCTX, _T("on device ud = '%d' failed"), ud); GPIBError (ud, FCTX, true); return false; } return true; } char TGpib::SerialPoll (Int ud) { char pollChr; Int stat = ibrsp (ud, &pollChr); if ((stat & ERR) != 0) { MCTraceLib (this, eTraceError, TFCTX, _T("on device ud = '%d' failed"), ud); GPIBError (ud, FCTX); return false; } return static_cast<char> (pollChr & 0x9F); // VM QueryError eliminieren } bool TGpib::DeviceClear (Int ud) { Int stat = ibclr (ud); if ((stat & ERR) != 0) { MCTraceLib (this, eTraceError, TFCTX, _T("on device ud = '%d' failed"), ud); GPIBError (ud, FCTX, true); return false; } return true; } bool TGpib::Trigger (Int ud) { Int stat = ibtrg (ud); if ((stat & ERR) != 0) { MCTraceLib (this, eTraceError, TFCTX, _T("on device ud = '%d' failed"), ud); GPIBError (ud, FCTX); return false; } return true; } bool TGpib::Send (Int ud, const std::string& str) { Int stat = ibeot (ud, 1); if ((stat & ERR) != 0) { MCTraceLib (this, eTraceError, TFCTX, _T("'EOI on' on ud = '%d' failed"), ud); GPIBError (ud, FCTX); return false; } stat = ibwrt (ud, (void*)str.c_str (), str.length ()); Long sent = ThreadIbcntl (); if ((stat & ERR) != 0) { MCTraceLib (this, eTraceError, TFCTX, _T("on device ud = '%d' failed"), ud); GPIBError (ud, FCTX); return false; } if (sent != static_cast<Long> (str.length ())) { MCTraceLib (this, eTraceError, TFCTX, _T("only %d of %d characters sent"), sent, str.length ()); return false; } return true; } bool TGpib::SendNoEOI (Int ud, const std::string& str) { Int stat = ibeot (ud, 0); if ((stat & ERR) != 0) { MCTraceLib (this, eTraceError, TFCTX, _T("'EOI off' on ud = '%d' failed"), ud); GPIBError (ud, FCTX); return false; } stat = ibwrt (ud, (void*)str.c_str (), str.length ()); Long sent = ThreadIbcntl (); if ((stat & ERR) != 0) { MCTraceLib (this, eTraceError, TFCTX, _T("on device ud = '%d' failed"), ud); GPIBError (ud, FCTX); return false; } if (sent != static_cast<Long> (str.length ())) { MCTraceLib (this, eTraceError, TFCTX, _T("only %d of %d characters sent"), sent, str.length ()); return false; } return true; } std::string TGpib::Enter (Int ud) { std::string str = ""; char* buf = new char[2048]; Int stat = ibrd (ud, (void*)buf, 2047); Long got = ThreadIbcntl (); if ((stat & ERR) != 0) { MCTraceLib (this, eTraceError, TFCTX, _T("on device ud = '%d' failed"), ud); GPIBError (ud, FCTX); } else { buf[got] = '\0'; str = buf; // eventuelle LF und CR vom Ende entfernen! string::size_type idx = str.find_last_of (k_CR); str = str.substr (0, idx); idx = str.find_last_of (k_LF); str = str.substr (0, idx); } delete[] buf; return str; }
01-27-2014 03:22 AM
Part 3:
//----- EnterNoTimeout ------------------------------------------------------------- std::string TGpib::EnterNoTimeout (Int ud, ULong timeoutMs) { std::string str = ""; char* buf = new char[2048]; TGpib_TimeoutSetter autoTimeout (this, ud, timeoutMs); Int stat = ibrd (ud, (void*)buf, 2047); Long got = ThreadIbcntl (); if ((stat & ERR) != 0) { if (stat == EABO) return str; MCTraceLib (this, eTraceError, TFCTX, _T("on device ud = '%d' failed"), ud); GPIBError (ud, FCTX); } else { buf[got] = '\0'; str = buf; // eventuelle LF und CR vom Ende entfernen! string::size_type idx = str.find_last_of (k_CR); str = str.substr (0, idx); idx = str.find_last_of (k_LF); str = str.substr (0, idx); } delete[] buf; return str; } SGpibDevInfo TGpib::DeviceInfo (Int ud) { SGpibDevInfo devInfo; devInfo.mGpibAdr = -1; GPIBDevMap::iterator it = mDevices.find (ud); if (it != mDevices.end ()) devInfo = it->second; return devInfo; } Int TGpib::ibask (Int ud, Int option, Int* value) { Int res = ::ibask (ud, option, value); if ((res & ERR) != 0) { MCTraceLib (this, eTraceError, TFCTX, _T("on device ud = '%d' failed"), ud); GPIBError (ud, FCTX); } return res; } Int TGpib::ibcmd (Int ud, void* cmdbuf, long count) { Int res = ::ibcmd (ud, cmdbuf, count); Long sent = ThreadIbcntl (); if ((res & ERR) != 0) { MCTraceLib (this, eTraceError, TFCTX, _T("on device ud = '%d' failed"), ud); GPIBError (ud, FCTX); } if (sent != count) MCTraceLib (this, eTraceError, TFCTX, _T("only %d of %d commands sent"), sent, count); return res; } void TGpib::GPIBError (Int ud, const Tstring& ctx, bool /*fatal*/) { if (ErrorFlag ()) return; SGpibDevInfo devInfo; devInfo.mGpibAdr = -1; if (ud >= 0) { GPIBDevMap::iterator it = mDevices.find (ud); if (it != mDevices.end ()) devInfo = it->second; } Int err = ThreadIberr (); if (err < 0 || err > kErrorMnemonics) { // err = kErrorMnemonics; ErrorMsg (ctx, _T("NI488 Fehler auf '%d': IBSTA = %d, IBERR = %d '%s'"), devInfo.mGpibAdr, ThreadIbsta (), err, _T("OOps") ); } else { ErrorMsg (ctx, _T("NI488 Fehler auf '%d': IBSTA = %d, IBERR = %d '%s'"), devInfo.mGpibAdr, ThreadIbsta (), err, ErrorMnemonic[err] ); } } Int __stdcall TGpib::GpibSRQ (Int, unsigned long sta, unsigned long err, unsigned long cntl, void* ptr) { TGpib* me = reinterpret_cast<TGpib*> (ptr); char poll = 0; GPIBDevMap::iterator it = me->mDevices.begin (); for (; it != me->mDevices.end (); ++it) { ibrsp (it->first, &poll); if ((poll & 0x40) != 0) break; } if (it != me->mDevices.end ()) { SGpibDevInfo devInf = it->second; devInf.mIbsta1 = sta; devInf.mIberr = err; devInf.mIbcntl = cntl; if (devInf.mSRQEvent != NULL) { if ((ibsta & ERR) == 0) devInf.mSerialPoll = poll; it->second = devInf; SetEvent (devInf.mSRQEvent); //return SRQI; } else { MCTraceLib (me, eTraceError, TFCTX, _T("not enabled device '%d' requested service"), devInf.mGpibAdr); } } else { MCTraceLib (me, eTraceDebug, TFCTX, _T("(SRQ)unexpected interrupt received! status = '%d' error = '%d'"), sta, err); } return 0; } } // namespace MC
Thanks and best regards
Walter
03-30-2014 07:35 AM
Were you able to generate a mini-dump with ni4882.dll on the stack? If you could provide this, it may help identify the cause of the failure.