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.