Instrument Control (GPIB, Serial, VISA, IVI)

cancel
Showing results for 
Search instead for 
Did you mean: 

Why does FreeLibrary() sometimes crash

I'm using VC++ 6.0 SP5 on my WinXP Pro to write a test program using the NI-488.2 device driver 2.1. I'm using "direct access" because when I run my test program on some of my customer's machines I don't know if NI-488.2 is installed or not. Even if NI-488.2 is installed I don't know if there are any NI interfaces installed.

In one of my constructors I try to load the "gpib-32.dll" to see if it exists. If it does then I run a series of ibfindA() calls to locate all the available "GPIBx" interfaces, and then unload the DLL. This works fine and hasn't failed (yet). The pseudo-code is shown below:

void Constructor (void)
(
if (LoadLibrary ("GPIB-32.DLL")
{
mark DLL found = TRUE;
Use ibfindA() to find all "GPIBx" interfaces
FreeLibrary()
}
}

However, when I run a series of tests using OpenBoard() (psuedo-code shown below) with the interface names "GPIB0" (which exists on my machine) and "NONE", eventually the call to FreeLibrary() causes one of those WinXP notifications to pop up and say "Gee - we're sorry but your application has a problem and needs to be shut down. Would you like to send a report to Microsoft?". Obviously, there are all kinds of validation checks in my real code - the psuedo-code just shows the steps used without all the overhead.

BOOL OpenBoard (pszName)
{

//---- disable current GPIBx interface ----

ibnotify (desc, 0, NULL, NULL)
ibonl (desc, 0)
mark desc as invalid

//---- enable new GPIBx interface ---------

if (pszName starts with "GPIB")
{
LoadLibrary ("GPIB-32.DLL")
desc = ibfindA (pszName)
ibconfig (desc, IbcSAD, 0)
ibconfig (desc, IbcPAD, address)
ibnotify (desc, LACS, CallBack, pParam)
}

//---- no valid interface name -----------

else
FreeLibrary()
}

This code may fail the first time or it may take many tries to get it to fail. But the Microsoft notification always happens very shortly (less than 1 second) after the call to FreeLibrary(). When it does fail I notice that the hour-glass cursor appears for just a very short time (blink and you'll miss it).

The only hint I have is by clicking on the "details" link in the notification and weeding through the data given there:

AppName: testnigpib.exe
AppVersion: 1.0.3.1
ModName: unknown
ModVer: 0.0.0.0
offset: 0x6401CEA7

Exception Information
Code: 0xC0000005
Flags: 0x00000000
Record: 0x0000000000000000
Address: 0x000000006401CEA7

If I had to guess this exception (0xC0000005 = access violation) is occurring in NIPALU.DLL because NIPALU.DLL has a base address of 0x64000000.

So now comes the questions: Are there any known issues with using FreeLibrary()? Do I have to do any "cleanup" before I call FreeLibrary()? This problem almost indicates that from the time I call my cleanup code (ibnotify() and ibonl()) until I call FreeLibrary() the NI DLL's haven't had time to do their housekeeping before the FreeLibrary() does its thing. I hope there are some good suggestions on things to try but I've tried to sort this thing our for 2 days now.

Thanks,
Mike
0 Kudos
Message 1 of 9
(12,826 Views)
Hey Mike,

The first thing that I noticed in your code is the following.

if (LoadLibrary ("GPIB-32.DLL")
{
....
FreeLibrary();
}

In this case you are always trying to load the library and you only free the library if it loaded successfully. This is correct. However, in you second implementation you have the following.

if (pszName starts with "GPIB")
{
LoadLibrary ("GPIB-32.DLL")
....
}
else
FreeLibrary()


In this case you only try to load the library if "GPIB" but you never free the library. In addition, if it is not "GPIB" you free a library that was never loaded. I am sure this is what is causing the crash. Perhaps the driver is loading twice, because it was never freed or you are telling it
to free a dll that was never loaded or perhaps it is freeing some other dll.

Regardless, I would suggest making the second section look like the original and it should work fine. I hope this helps out.

JoshuaP
National Instruments
0 Kudos
Message 2 of 9
(12,826 Views)
Hi Joshua,

I was afraid my pseudo-code would' be complete enough. You're correct in your analysis though but in order to simplify I left out a lot of the overhead and checks. The biggest thing I left out is:

if (!m_hGPIB)
m_hGPIB = LoadLibrary ("GPIB-32.DLL");

and

if (m_hGPIB)
{
FreeLibrary (m_hGPIB);
m_hGPIB = NULL;
}

Again, I left out some of the overhead stuff to keep the logic as simple as possible.

The thing I'm trying to accomplish is that if the DLL isn't needed (as in the case when "NONE" is the name of the interface) then I free it. If the interface name contains "GPIB" then I load the DLL but only if it isn't already loaded. This works just like I want it to and I've double- and triple-checked the load/unload lo
gic by looking at all the DLLs loaded into memory. But the problem still occurs every once in a while when I call FreeLibrary().

I hate to even say this but as a test (just because of the things I noticed when I was testing) I put in a Sleep(250) just before the call to FreeLibrary() and I haven't had the failure since. It still acts like the NI DLLs don't have time to do their housekeeping before the FreeLibrary() does its thing. This is a bad "fix" but I only did it to test a theory. I'm still trying to figure out how to best fix the problem.

Thanks,
Mike
0 Kudos
Message 3 of 9
(12,826 Views)
Hey Mike,

There are several asynchronous functions that the driver could be processing. Functions such as ibnotify, ibcmda, ibrda, and ibwrta. If the driver is in the process of moving data to and from the device it could really cause problems if it was unloaded.

When your using ibnotify make sure you disable the callback before freeing the dll.

// disable notification
ibnotify (desc, 0, NULL, NULL);

To test this theory you might want to try an ibstop before you free the dll and check the error that is returned. If it has an error then it was probably performing an operation.

I hope this helps out.

JoshuaP
National Instruments
0 Kudos
Message 4 of 9
(12,826 Views)
Hi Joshua,

In fact my code does this (again, all the overhead has been left out):

ibnotify (desc, 0, NULL, NULL);
ibonl (desc, 0);
FreeLibrary (m_hGPIB);

Your idea of using ibstop() is worth exploring. I suspect that the place to use it would be just after "ibnotify (desc, 0, NULL, NULL)". I'll give it a try.

Thanks,
Mike
0 Kudos
Message 5 of 9
(12,826 Views)
Joshua,

Well, I used ibstop() and the FreeLibrary() problem still occurs from time to time. I put Sleep() back in just before FreeLibrary() and haven't had a failure yet. It still looks like the NI DLLs are doing something when FreeLibrary() is called and that's what is giving me the Microsoft notification.

Mike
0 Kudos
Message 6 of 9
(12,826 Views)
Hey Mike,

With everything that you have done up to this point, it looks like adding the wait might be the best option in this application. Out of curiosity are you using GetProcAddress to define the functions?

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore98/html/_core_loadlibrary_and_afxloadlibrary.asp

JoshuaP
0 Kudos
Message 7 of 9
(12,826 Views)
Hi Joshua,

I really hate (and I mean HATE) to leave the Sleep() call in my code but I don't know what else to do.

Yep, I'm using GetProcAddress() to get all the function pointers in the DLL. I had already looked at the difference between LoadLibrary() and AfxLoadLibrary() and settled on LoadLibrary(). Seems that AfxLoadLibrary() is really only needed for loading extension DLLs.

I would really like to find out why this problem shows up from time-to-time but I don't have any tools to help me really find out what's going on.

Mike
0 Kudos
Message 8 of 9
(12,826 Views)
Hey Mike,

One thing you might want to try is a Sleep(0). The thread will relinquish the remainder of its time slice but remain ready. It�s possible you just need to let the system process other events that might be queued up. This shouldn't slow your code down, but just give the system time to process some of the other methods that might be executing on the DLL.

In CVI there is a similar function called ProcessSystemEvents that basically allows the processor to perform functions on threads that have lower priorities. In most cases we just us this to allow the computer to refresh the screen, but it might help in this case as well if you are using CVI.

I hope this helps out.

JoshuaP
0 Kudos
Message 9 of 9
(12,826 Views)