LabWindows/CVI

cancel
Showing results for 
Search instead for 
Did you mean: 

FTDI: Failing to load libMPSSE.dll

Solved!
Go to solution

 

TL&DR: Failing to load libMPSSE.dll

 

The Problem:
I'm not sure where to turn for help since my problem spans FTDI and LabWindows. I've joined a collaboration containing some LabWindows-based source code that will utilise FTDI devices to exercise the SPI protocol on a hardware board. I can compile the source code and I have plugged in a UM232H-B device to my Windows machine, as an intermediate step to run the source code (hardware board not yet available). However, when I run the code it's failing to load the libMPSSE.dll. A snippet of the code throwing the error is:

 

#ifdef _WIN32
	#ifdef _MSC_VER
		h_libMPSSE = LoadLibrary(L"libMPSSE.dll");
	#else
		h_libMPSSE = LoadLibrary("libMPSSE.dll");	// Returns NULL
	#endif

 

What I tried:
The DLL in question is in the root folder of the source code, all files are in the same folder. I assumed I made a mistake with installing the FTDI drivers, but I can program the EEPROM on my device using FTDI's FT_Prog tool. Also, I can read back what I've written to the EEPROM, by building the Microsoft visual studio-based example that comes with the software examples (https://ftdichip.com/software-examples/mpsse-projects/libmpsse-spi-examples/ )

 

I am aware that FTDI will only allow access either through VCP (Virtual Com Port) or through the D2XX drivers (of which libMPSSE.dll is one). I have unticked "load VCP" through the Device Manager -> Universal Serial Bus controller -> USB Serial Converter, Properties, Advanced tab. Which previously prevented me from programming the EEPROM.

 

Looking at the structure of the visual studio example, it is copying the DLL into the same folder where it generates its executable. Examining LabWindows, it generates the executable into two different folders. First off, to the parent folder containing the source code. But also to the "cvibuild.project-name\Debug" subfolder (where project-name is the name of the project), which LabWindows generates when the project is first built. LabWindows appears to use the executable from the parent folder when I debug the project. The DLL already resides in that folder. I have tried copying the DLL into the Debug folder too, but that makes no difference.

 

So I'm left scratching my head. This *should* work, because it runs on a Windows 8 PC that I cannot access. I've got Windows 10, so is there a substantial difference between the OSs? Or LabWindows (I've got 2017)? Is it possible there is a setting in a file that I failed to copy across? (But it does build and run..).

 

Any help or pointers would be greatly appreciated. Thanks for reading through all of this!

0 Kudos
Message 1 of 14
(5,152 Views)

First the #ifdef _MSC_VER is absolutely wrong.

 

_MSC_VER is if you are using a Microsoft compiler or not, the code difference you have is dealing with the fact that by default when using a Microsoft Compiler, the UNICODE define is active. You should never attempt to work around compiler problems by depending on only loosely related precompiler defines. If you compile this program with a Microsoft compiler where you have UNICODE undefined this will cause problems.

 

More correct would be something like

 

#ifdef _WIN32
    h_libMPSSE = LoadLibrary(_T"libMPSSE.dll");
#else
    h_libMPSSE = dlopen("libMPSSE.so");
#endif

 

The _T expands to an L if UNICODE is defined, and to nothing if it is not defined. And LoadLibrary expands to LoadLibraryW with UNICODE defined and LoadLibraryA with UNICODE not defined. This is how Microsoft has designed these macros to work, and will basically cause the C compiler to see the equivalent of this:

#ifdef _WIN32
    #ifdef UNICODE
        h_libMPSSE = LoadLibraryW(L"libMPSSE.dll");
    #else
        h_libMPSSE = LoadLibraryA("libMPSSE.dll");
    #endif
#else
    h_libMPSSE = dlopen("libMPSSE.so");
#endif

Your code without UNICODE defined, will call LoadLibraryA() with a Unicode string. That obviously can not result in a valid path for the LoadLibraryA() function as the Unicode string will be interpreted as an ASCII string and converted to Unicode before being passed to the relevant Windows kernel APIs. Basically this will result in an Unicode string only containing the first character of the path being passed to the kernel API. And LoadLibrary("l") obviously can not point to a valid DLL at all.

 

Also the else case in your code is at least questionable. Any compiler claiming to support Win32 programming should come with the according Windows SDK headers and therefore be able to expand the standard Windows Unicode macro magic, or it is a very useless Win32 compiler.

Rolf Kalbermatter
My Blog
Message 2 of 14
(5,115 Views)

Thank you very much for the detailed answer - unfortunately I only caught it at the end of the working day. I quickly tried the examples you gave and it does indeed appear like UNICODE is not defined in my compiler. For the second snippet, it attempts to call LoadLibraryA() which again returns NULL.

 

I couldn't try your first example as _T is undefined (checking online, I think it resides in tchar.h but it's unavailable with my compiler). I think I wasn't clear in pointing out that I using LabWindows/CVI 2017 to build the source code. I'll have a much more thorough look tomorrow.

0 Kudos
Message 3 of 14
(5,097 Views)

Have you installed the Windows SDK support for LabWindows/CVI? Although I think LabWindows won't support Unicode anyhow, it didn't last I really used it, which is many years ago.

 

But since you say that even the LoadLibraryA() call returns NULL, this basically means that Windows was not able to load the libMPSSE.dll. Have you installed the FTDI drivers properly?

 

Windows will only search for DLLs loaded with a relative path in a few specific locations. The first is the process executable directory which is where your LabWindows CVI created executable is located. The other meaningful location is in the <System> directory, usually "C:\Windows\SysWOW64"  for a 32-bit application and "C:\Windows\System32" for a 64-bit application. Another location it will search is any directory mentioned in the PATH environment variable. If your DLL is located anywhere else you have to pass the full path to LoadLibrary() or Windows will not find it. Also libMPSSE.dll is only a higher level library that depends and requires the FTDI low level d2xx driver library to be installed as well on your computer, which will usually be installed in the according <system> directory.

 

 

Rolf Kalbermatter
My Blog
Message 4 of 14
(5,092 Views)

Installing Windows SDK is separate from LabWindows/CVI (no options for it in NI's setup wizard). I had to remind myself how to find out which version(s) of the SDK(s) I've got on my machine. If I open an outdated Microsoft Visual Studio Project, I'm given the option to upgrade to either 10.0.17763.0 or 8.1. Checking my registrey (https://stackoverflow.com/a/27803419397, Tom's addition), my current version is 8.0.50727 and I've got LabWindows/CVI 2017 installed.

 

The Windows 8 PC that is able to use the DLL has SDK version 6.3.9600 and LabWindows/CVI 2019. I suspect the SDK difference may play a part, assuming my FTDI installation is sound. I'm not 100% confident I've got the FTDI drivers installed correct, but I am able to use their FT_Prog utility (to program the eeprom on my UM232H-B device, and read back the new values). I can also run the Visual Studio SPI example and read the new values off the eeprom.

 

I'll address the rest tomorrow. I unexpectedly (short notice) ended up moving office so my brain's a bit fried now. Thank you very much for sharing your expert knowledge.

0 Kudos
Message 5 of 14
(5,059 Views)

Chrang_0-1621954930772.png

Sorry, just realised I'm not sure whether that Windows 8 machine is running Windows SDK version 6.3 or 8.1...

Above is a screenshot of the relevant registry entry.

0 Kudos
Message 6 of 14
(5,058 Views)

Well, don't get to involved with the SDK. It's mostly about the UNICODE define only and I don't think LabWindows/CVI even supports Unicode, so it is a pretty moot point.

 

However, when you just specify the DLL name to LoadLibrary() the DLL needs to either be in the same directory as where your EXE file is, so not alongside the sources but besides your EXE file, or it can also be in the <System> directory. You also can add the directory where your DLL resides, to the PATH environment variable but that it very much MS-DOS time.

Rolf Kalbermatter
My Blog
Message 7 of 14
(5,040 Views)

I think my FTDI drivers must be properly installed. When I run the setup, I am not given any options where to place the files. I do see libMPSSE.dll, ftd2xx.dll both in my Windows\System32 as well as my windows\SysWOW64. The LibMPSSE.dll in my System32 folder was actually 32 bits (it should be 64) otherwise they were as expected. I corrected that to be the 64-bit version, no difference. I am able to use the EEPROM programming utility, FT_Prog. I am also able to run the libMPSSE Visual Studio example, and read back the Product Description that I changed through FT_Prog. If I messed up the drivers installation, I'm not sure how.

 

I see that LabWindows creates my project's executable both in the source code folder, and in the subfolder that it creates, "cvibuild….\Debug". But it is the executable in the source code folder that is being run when I am debugging my project. The DLLs are in the source code folder, but I also copy them into the "cvbuild…\Debug" folder. Makes no difference.

 

I have confirmed that UNICODE is not defined, neither on my system or on the Windows 8 system. I'm running LabWindows 2017, the other systems running LabWindows 2019. I'll keep digging tomorrow.

0 Kudos
Message 8 of 14
(5,024 Views)
Solution
Accepted by topic author Chrang

Well it turns out that the very same version of the DLL makes a hell of a difference depending on which location it happens to be in. If it's in my source code folder, LabWindows on my machine is unable to load the DLL file. If it's in my Windows folder [1], C:\Windows\SysWOW64, then things work just fine. I have verified this by, in turn, deleting one of the locations, try my program and then rinse and repeat with the first location reinstated and deleting the second location. I can't explain whether this is a difference between LabWindows 2017 and 2019 (the windows 8 machine has no issues with the DLL in the source code folder). If I write the simplest of programs to just load the module (a one line programme, ignoring the #includes) then I've no problems getting LoadLibrary() to work using the DLL in the same folder as the simple program. Both in Visual Studio and in LabWindows. Just not with this project. There is also some kind of caching going on with LabWindows (or elsewhere) so some changes will not take effect immediately.

 

This is thoroughly puzzling but at least I resolved my issue. On the windows 8 machine, leave the DLL in the source code folder. On my Windows 10 machine, delete the DLL from the source code folder. Hopefully this will prove useful for someone in the future.

 

[1] = 32-bit

 

0 Kudos
Message 9 of 14
(4,966 Views)

There is likely something else going on than what you think.

 

The source code folder of an application is totally irrelevant for Windows to find a DLL when you pass a relative path to the LoadLibrary() function. Windows has only a few locations it will search for such a DLL.

 

1) check for the DLL name in memory

2) check in the process directory (where the executable for your current process is located)

3) check in the <system> directory

4) check in the <windows> directory

5) check in any directory that is contained in the PATH environment variable

 

Depending on Windows version and flags configured for the DLL loader though there is one other directory that is searched either early on or late in this list which is called the <current directory>. This is IMHO a stupid idea to use as the <current directory> is a process global variable that is initialized by default to the process directory, unless the CreateProcess() call received a specific default directory to use and this can also be changed with a Windows API call. But the most stupid thing in Windows is that the File Dialog also changes this directory to whatever directory it was in whenever it is dismissed by the user acknowledging the file or directory selection.

 

So when your last file dialog in LabWindows/CVI was selecting a file (no matter what type of file) in the same directory as your DLL is located, the LoadLibrary("libMPSSE.dll") call will happily succeed. If you selected a file in a different directory (or none at all, since then the current directory will still be set to the directory where your cvi.exe is located), it won't!

 

Another option might of course be that someone "smart" added that directory to the PATH environment variable on your Windows 8 machine and everything worked magically. Until some other person comes along and installs everything on a different machine and nothing works anymore.

 

Possible solution are twofold:

 

1) Keep using your relative DLL path but don't rely on Windows finding it in any other location than one of the 5 in above list.

2) Build an absolute path to the DLL where you know you placed it and pass that to LoadLibrary().

Rolf Kalbermatter
My Blog
0 Kudos
Message 10 of 14
(4,944 Views)