Gribo Posted August 26, 2015 Report Share Posted August 26, 2015 Hello, I wrote an application which can use either a 32 bit or a 64 bit dll, it loads the dll from a path specified in an INI file. This code works properly on the development machine (LV2013, both 32 and 64 bit, both with a debugger and as an EXE) but doesn't work on the tester machine as an executable. It throws error code 13 (in LV2013 - file is not a resource, in LV2014 - Failed to load DLL due to invalid format or missing dependencies). However, when I change all the Invoke nodes to use a static predefined path, everything is OK. What am I doing wrong here? I rather maintain one code base and build for each target than maintain a code for each target. The API dll is from signalhound.com http://signalhound.com/spike Quote Link to comment
eberaud Posted August 26, 2015 Report Share Posted August 26, 2015 If you use the conditional structure with TARGET_BITNESS, the selection happens at compile time. Now you need 2 computers: one to build the 32 bit version and one to build the 64 bit version. Wouldn't it make more sense to use a case structure and detect the bitness of the PC on which the application is being executed? To do that, I use the tip given by rolfk in this thread: https://lavag.org/topic/14002-determine-32-or-64bit-os-windows/ Quote Link to comment
ShaunR Posted August 26, 2015 Report Share Posted August 26, 2015 (edited) If you use the conditional structure with TARGET_BITNESS, the selection happens at compile time. Now you need 2 computers: one to build the 32 bit version and one to build the 64 bit version. Wouldn't it make more sense to use a case structure and detect the bitness of the PC on which the application is being executed? To do that, I use the tip given by rolfk in this thread: https://lavag.org/topic/14002-determine-32-or-64bit-os-windows/ LabVIEW 32 bit can only load 32 bit dlls regardless of your platform bitness - although you can't install LabVIEWx64 on Win32. You don't need two computers, you need two LabVIEW versions to compile both 32 and 64 bit executables that will then use the 32 and 64 bit dll respectively. That's why we use the conditional disable because only the end developers' (not the end users') bitness counts for when they compile the executable. Bottom line: Executables are either 64 OR 32 bit and each can only use the corresponding DLLs.of that bitness For the OP. I expect the paths are not what you're expecting them to be or you are missing some dependencies of the DLL. Edited August 26, 2015 by ShaunR 1 Quote Link to comment
Rolf Kalbermatter Posted August 26, 2015 Report Share Posted August 26, 2015 Hello, I wrote an application which can use either a 32 bit or a 64 bit dll, it loads the dll from a path specified in an INI file. This code works properly on the development machine (LV2013, both 32 and 64 bit, both with a debugger and as an EXE) but doesn't work on the tester machine as an executable. It throws error code 13 (in LV2013 - file is not a resource, in LV2014 - Failed to load DLL due to invalid format or missing dependencies). However, when I change all the Invoke nodes to use a static predefined path, everything is OK. What am I doing wrong here? I rather maintain one code base and build for each target than maintain a code for each target. The API dll is from signalhound.com http://signalhound.com/spike Where would the paths be located? There exists something like files system redirection in Windows VISTA and higher which will redirect certain paths like C:\Windows\System32 or C:\Program Files and C:\Program Files (x86) to whatever the kernel considers the appropriate location for the current application based on its bitness. So eventhough you ask for C:\Windows\System32 in a 32 bit process, it will be directed to C:\Windows\SysWOW64 when run on a 64 bit OS! It's possible that LabVIEW attempts to be smart when trying to reference a DLL that is defined in the Call Library Node but won't second guess Windows decision when you define the dynamic path. 1 Quote Link to comment
Gribo Posted August 26, 2015 Author Report Share Posted August 26, 2015 There is also an .INI file which directs to the API install path. It has just one line. C:\program files (x86)\signal hound\spike\api. I verified that the generated path is ok. Rolfk, this might explain why the same code works with the invoke nodes having the DLL path predefined. It should have behaved the same in both cases, or, at least report a file not found error (#7). I even tried placing the DLL in the same directory as the executable, which is one of the location windows searches for them, and got the same error. Quote Link to comment
ShaunR Posted August 26, 2015 Report Share Posted August 26, 2015 There is also an .INI file which directs to the API install path. It has just one line. C:\program files (x86)\signal hound\spike\api. I verified that the generated path is ok. Rolfk, this might explain why the same code works with the invoke nodes having the DLL path predefined. It should have behaved the same in both cases, or, at least report a file not found error (#7). I even tried placing the DLL in the same directory as the executable, which is one of the location windows searches for them, and got the same error. That's the 32 bit directory on a Win64 platform. What is the LabVIEW bitness that you created the Executable with? Quote Link to comment
Rolf Kalbermatter Posted August 26, 2015 Report Share Posted August 26, 2015 There is also an .INI file which directs to the API install path. It has just one line. C:\program files (x86)\signal hound\spike\api. I verified that the generated path is ok. Rolfk, this might explain why the same code works with the invoke nodes having the DLL path predefined. It should have behaved the same in both cases, or, at least report a file not found error (#7). I even tried placing the DLL in the same directory as the executable, which is one of the location windows searches for them, and got the same error. Shaun already told you that this is a 32 Bit path. A 64 bit application will attempt to load "C:\program files\signal hound\spike\api\..." no matter what you do. As to error codes: LabVIEW does sometimes second guess Windows error codes and attempts to determine a more suitable code, also when loading shared libraries but that has to end at some point. Otherwise they could start to reimplement whole parts of Windows, that is actually easier than to try to second guess system API error codes which also can vary between OS versions and even depending on system extensions which can or can not be installed. There is a possibility to disable file system redirection temporarly through Wow64DisableWow64FsRedirection() which LabVIEW might do when loading an explicit DLL defined in the Library Path of the CLN confiiguration (at least as a secondary attempt if the normal load fails). However this is a thread global setting. Loading of DLLs that are explicitiedly named in the configuration dialog happens at load time of the VI, which is a highly serialized operation with all kinds of protection locks in place inside LabVIEW to make sure there won't be any race conditions as LabVIEW updates its internal bookkeeping tables about what resources it has loaded etc. The loading of DLLs that are passed as path to the CLN has to happen at runtime and executes in the context of the thread that executes the CLN call and other parts of the diagram if the CLN is set to execute reentrantly, otherwise it has to compete with the GIU update which also does all kind of things that could get badly upset with the file system redirection disabled. So while it can be safe to temporarly disable file system redirection during VI load time, this is a much more complicated issue at runtime and the safe thing here is to simply not do it. It is even less safe to wrap your CLN with an additional CLN call to a Wow64DisableWow64FsRedirection()/Wow64RevertWow64FsRedirection() call since you either have to execute all 3 CLNs in the UI thread to make sure they operate as intended and that could influence other things in LabVIEW that happen in the UI thread between calls to your CLN. If you set the CLN calls to run as reentrant they will most likely not run in the same thread at all as LabVIEW executes diagram clumps in random threads within an execution system thread pool. There are only two ways to make this still work if you need to disable file system redirection. One is to write a DLL that your CLN calls which calls first Wow64DisableWow64FsRedirection() then attempts to load the DLL with LoadLibrary() then calls Wow64RevertWow64FsRedirection() and then calls the function. The other is to create a subVI with subroutine execution and pack the Wow64DisableWow64FsRedirection() , CLN call and Wow64RevertWow64FsRedirection() in it. Subroutine VIs are guaranteed to be executed in one go without any thread switching during the execution of the entire subroutine diagram. More precisely though, your API installation is broken. Installing 64 bit DLLs inside "Program Files (x64)" is very BAD, as well as installing 32 bit DLLs inside "Program Files" or "Windows\System32" on a 64 bit system. Quote Link to comment
eberaud Posted August 26, 2015 Report Share Posted August 26, 2015 Coincidence, I'm actually facing a related issue right now. My application is compiled in 32-bit and runs nicely on both 32-bit and 64-bit machines. However one new plugin I created calls a 3rd-party dll which has been provided by the supplier in both 32-bit and 64-bit versions. My code was calling either one or the other, based on the OS bitness. But now I understand from what I read that a 32-bit application cannot call a 64-bit dll. So my question is: do you think there is a way to use the 32-bit dll on the 64-bit machine? Right now the dll lives in a sub-folder in C:\. Should I move it to ProgramFiles(x86)? (the application always lives on ProgramFiles(x86). Sorry to hijack the thread a little bit. Quote Link to comment
Rolf Kalbermatter Posted August 26, 2015 Report Share Posted August 26, 2015 Coincidence, I'm actually facing a related issue right now. My application is compiled in 32-bit and runs nicely on both 32-bit and 64-bit machines. However one new plugin I created calls a 3rd-party dll which has been provided by the supplier in both 32-bit and 64-bit versions. My code was calling either one or the other, based on the OS bitness. But now I understand from what I read that a 32-bit application cannot call a 64-bit dll. So my question is: do you think there is a way to use the 32-bit dll on the 64-bit machine? Right now the dll lives in a sub-folder in C:\. Should I move it to ProgramFiles(x86)? (the application always lives on ProgramFiles(x86). Sorry to hijack the thread a little bit. Your code should ALWAYS call the DLL which has the same bitness your application was compiled in. So if you used LabVIEW 32 bit to create your application (or run your VI in LabVIEW 32 bit) you MUST reference the 32 bit DLL, independent if you run on 32 bit or 64 bit Windows. A 32 bit process CANNOT load a 64 bit DLL (for code execution that is, but that is all you care about!) nor can a 64 bit process load 32 bit DLLs. The problem is not about a 32 bit DLL living somewhere in a random subdirectory, but about a 32 bit DLL living in a directory that a 64 bit system considers reserved for 64 bit code, such as "C:\Program Files\..." or "C:\Windows\System32" and 64 bit DLLs living in a location that the 64 bit system considers reserved for 32 bit code, such as "C:\Program Files (x86)\.." or "C:\Windows\SysWOW64". If you have a 32 bit system those file system redirections do not apply but any 64 bit code file anywhere will be considered an invalid executable image file. Quote Link to comment
ShaunR Posted August 26, 2015 Report Share Posted August 26, 2015 (edited) Coincidence, I'm actually facing a related issue right now. My application is compiled in 32-bit and runs nicely on both 32-bit and 64-bit machines. However one new plugin I created calls a 3rd-party dll which has been provided by the supplier in both 32-bit and 64-bit versions. My code was calling either one or the other, based on the OS bitness. But now I understand from what I read that a 32-bit application cannot call a 64-bit dll. So my question is: do you think there is a way to use the 32-bit dll on the 64-bit machine? Right now the dll lives in a sub-folder in C:\. Should I move it to ProgramFiles(x86)? (the application always lives on ProgramFiles(x86). Sorry to hijack the thread a little bit. And just to follow on from Rolph wise words. If you are using LabVIEW x32, you don't care about 64 bit DLLs because you can't use them and yes, you are fine working with the 32 bit DLL in 32 bit LabVIEW on a 64 bit Windows machine.. It just if you are developing DLLs that it is a. consideration because if you supply only a 32 bit DLL, people with 64 bit LabVIEW can't load the DLL in a CLFN. As to where to place them. Well. I place them where I damn well choose and always in the same directory as the application and with my own name (usually namex32.dll and namex64.dll if they have to coexist) because, well, it just save lots of hassle with DLL hell. Edited August 26, 2015 by ShaunR Quote Link to comment
eberaud Posted August 26, 2015 Report Share Posted August 26, 2015 Thanks to both of you. I will have to print and frame this golden rule! Quote Link to comment
Gribo Posted August 27, 2015 Author Report Share Posted August 27, 2015 I compiled both 32 and 64 bits, the 64 bit works without a problem. I think I will rename the DLL themselves, as Shaun suggested. This solution smells like a hack, what happens after a software update? The programmer needs to remember to rename these files? I tried to be smart. Quote Link to comment
Gribo Posted August 30, 2015 Author Report Share Posted August 30, 2015 Ok, I managed to get the code above to work properly. There was a missing x86 VC2010 runtime dll on the target computer. the x64 was installed as a default, so I had to explicitly install the x86 too. Quote Link to comment
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.