I discovered this issue after trying to compile my program in release mode using Qt 5.4 using MSVC 2013 32bit. Up until now everything has worked fine in debug, but I am having error code: 0xc0000409 thrown every time I try to run it in release. It looks like this usually means there are initialized variables somewhere, so I set breakpoints through my code to see where the issue is. What I discovered is that in the constructor of one of my classes, if I set a breakpoint on every line, it starts somewhere in the middle and skips where I am initializing my variables for that object. Here is the code:
#ifndef AD5932DDS_H
#define AD5932DDS_H
#include "adicyusbusb4.h"
#include <QObject>
#include "picosignal.h"
#include <QLibrary>
class AD5932DDS : public QObject
{
Q_OBJECT
public:
AD5932DDS(QObject *parent = 0);
~AD5932DDS();
private:
QLibrary *myLib;
unsigned int handle;
VendorRequestFunction Vendor_Request;
DisconnectFunction Disconnect;
SearchFunction Search_For_Boards;
ConnectFunction Connect;
DownloadFWFunction Download_Firmware;
};
#endif // AD5932DDS_H
AD5932DDS::AD5932DDS(QObject *parent) : QObject(parent)
{
int searchErrorCode = 0;
int connectErrorCode = 0;
int downloadErrorCode = 0;
unsigned int num_boards = 0;
handle = 0;
char pcFilePath[] = "C:\\Users\\Jason\\Documents\\Development\\Qt\\CrackDetection\\AD593x.hex";
char path = 0;
myLib = new QLibrary;
myLib->setFileName("ADI_CYUSB_USB4.dll");
Search_For_Boards = (SearchFunction) myLib->resolve("Search_For_Boards");
Connect = (ConnectFunction) myLib->resolve("Connect");
Download_Firmware = (DownloadFWFunction) myLib->resolve("Download_Firmware");
Vendor_Request = (VendorRequestFunction) myLib->resolve("Vendor_Request");
Disconnect = (DisconnectFunction) myLib->resolve("Disconnect");
if (!Search_For_Boards || !Connect || !Download_Firmware || !Vendor_Request || !Disconnect)
{
myLib->unload();
}
searchErrorCode = Search_For_Boards(VID, PID, &num_boards, &path);
if (num_boards > 0)
{
connectErrorCode = Connect(VID, PID, path, &handle);
if (connectErrorCode == 0)
{
downloadErrorCode = Download_Firmware(handle, pcFilePath2);
}
}
}
If I step through the debug build of these, the first line it breaks on is the line above
char pcFilePath[] = "C:\\Users\\Jason\\Documents\\Development\\Qt\\CrackDetection\\AD593x.hex";
It will then go back to the top and continue down as normal and everything works fine.
However, in release mode if I put
QMAKE_CXXFLAGS_RELEASE = $$QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO
QMAKE_LFLAGS_RELEASE = $$QMAKE_LFLAGS_RELEASE_WITH_DEBUGINFO
in the .pro file to allow breakpoints while debugging the release version the first breakpoint to be hit is
handle = 0;
From here it steps down,skipping the initialization above it, in order to
myLib = new QLibrary;
myLib->setFileName("ADI_CYUSB_USB4.dll");
where it hits both of these twice before continuing on. One thing I am noticing is that even after
Search_For_Boards = (SearchFunction) myLib->resolve("Search_For_Boards");
Connect = (ConnectFunction) myLib->resolve("Connect");
Download_Firmware = (DownloadFWFunction) myLib->resolve("Download_Firmware");
Vendor_Request = (VendorRequestFunction) myLib->resolve("Vendor_Request");
Disconnect = (DisconnectFunction) myLib->resolve("Disconnect");
is run, if I check the name and values for these, each of these list under value. So this makes me think maybe every issue stems from try to access this dll.
The dll came from here https://ez.analog.com/thread/11089 where after much trial and error, I was able to figure out how to use the dll when it didn't provide a static library or a header file with prototypes. What I did is create my own prototypes in a header file like this:
#ifndef ADICYUSBUSB4_H
#define ADICYUSBUSB4_H
const unsigned int VID = 0x0456;
//const unsigned int PID = 0xB20B; // EVAL-AD5932EBZ
const unsigned int PID = 0xB205; // EVAL-AD5930EBZ
const unsigned char WRITE = 0xDD;
const unsigned char SET_STANDBY_PIN = 0xDC;
const unsigned char CLEAR_STANDBY_PIN = 0xDB;
const unsigned char PULSE_CONTROL_PIN = 0xDA;
const unsigned char SET_CONTROL_PIN = 0xD9;
const unsigned char CLEAR_CONTROL_PIN = 0xD8;
const unsigned char PULSE_INTERRUPT_PIN = 0xD7;
typedef unsigned int (*SearchFunction) (unsigned int, unsigned int, unsigned int *, char *);
typedef int (*ConnectFunction) (unsigned int, unsigned int, char, unsigned int *);
typedef int (*DownloadFWFunction) (unsigned int, char []);
typedef int (*VendorRequestFunction) (unsigned int, unsigned char, unsigned short, unsigned short, unsigned char, unsigned short, unsigned char *[]);
typedef int (*DisconnectFunction) (unsigned int);
#endif // ADICYUSBUSB4_H
This method has worked great in debug mode, but something just isn't right for release.
So either I am handling this dll improperly (though it works great in debug mode) or my program is skipping some variable initialization for some unknown reason.
Don't rely on breakpoints or stepping through when compiled with optimizations turned on. Optimizers will change, reorder or remove statements. Don't spend too much time trying to analyze the flow of a program that was compiled with optimizations.
Is QLibrary
failing in some way? Check isLoaded()
and log the return value of the various resolve()
calls. You are calling unload()
in case of failure, but you're merrily executing the rest, trying to dereference null pointers.
Can you tell exactly where it's crashing? Try to output something to the console between every statement using an unbuffered stream, such as std::cerr
.
It could be something as stupid as your working directory being different and the DLL failing to load.
I believe 0xc0000409 indicates stack corruption, which could have resulted from various causes beyond just uninitialized variables.
Since you note you've had to manually create a DLL header, there's a possibility that it doesn't completely match what the DLL was actually implemented as. Beyond things like parameter count/types and return type, there is the calling convention. Since you don't specify one, you'll get whatever MSVC's default is. However if that DLL was compiled with something that chose a different convention, then that mismatch will cause problems.
In fact, a likely result is stack corruption. I can't say for sure this is your problem, but I believe it would be consistent with your 0xc0000409 error.
Ideally the provider of that DLL would be able to supply the correct information. (Or at a minimum, if you could find out what compiler they used then you could research its default calling convention.)
But if they can't or won't, then you may have to resort to trying different ones and seeing which appears to work correctly.
You're declaring variables right inside the constructor. Constructors are only for initializing a variable, so try changing that (declaring serves no purpose in a constructor, especially a default one)
User contributions licensed under CC BY-SA 3.0