09-28-2024 06:11 PM
I guess wrapper dll it is.
Only have to do for 64 bit.
there are samples here
examples\Connectivity\Libraries and Executables\Source C Files\
so I guess will be some input cluster and output array
09-29-2024 03:20 AM
do I actually have to use visual studio for this? Its 6GB for a friggin C++ compiler and does not even include the function names
https://forums.ni.com/t5/LabVIEW/LabVIEW-can-t-find-function-in-dll/td-p/839473
spent all day just to get sum = a + b compiled and some .h file added.
c compiler one can find with like 50MB installer...
09-29-2024 03:38 AM - edited 09-29-2024 03:57 AM
No you don’t but the alternatives are usually GCC based and the GCC folks always had an ambivalent feeling towards Windows.
The mentality of: a REALl programmer is just using the frigging command line or goes through the joy of installing an additional make environment is pretty strong. And that command line has to be of course Gnu based so add another extra joyful installation. And besides real programmer go Unix so don’t try to make it to pleasant for anyone insisting on using Windows!
50MB for a bare metal C compiler installation is maybe possible but don’t expect to call Windows API functions, the Windows SDK weights in at several 100 MB alone very easily! And don’t expect to do much more either! 50MB was reasonable 20 years ago, nowadays the manpages and other documentation alone will weight in with more!
Also while this C++ library doesn’t really make use of object classes with methods it is still C++ and there is no universally defined ABI that all C compiler builders adhere to. So it is never guaranteed that you can call C++ libraries from another compiler than what the library is created with, under some conditions not even different versions of the same compiler family. Welcome in the exciting world of C(++) compilers! 😀
09-29-2024 04:03 PM
well I am not a real programmer, my role is to explain to a real programmer how to wire a sensor that has 2 wires.
C++ is really exciting, copied some very simple code examples in, would not even compile that. Seems syntax is not even identitical between compilers.
Ok, that new dll has been just released, the olt SOAP based stuff will slowly die, still got time to somehow make a wrapper. Seems to ve very delicate business, some simple vis from the wizzard even crash, only meant to put in one string and det some string in retursn, but seems was not declared as expected. Anyway, that no longer involves Labview
09-30-2024 02:07 AM - edited 09-30-2024 02:19 AM
@Steffen01 wrote:
Ok, that new dll has been just released, the olt SOAP based stuff will slowly die, still got time to somehow make a wrapper. Seems to ve very delicate business, some simple vis from the wizard even crash, only meant to put in one string and det some string in retursn, but seems was not declared as expected. Anyway, that no longer involves Labview
The Import Library Wizard is NOT a magician. But to be able to import functions perfectly from only a header file would require magic abilities or the experience of some well versed C programmer, together with knowledge that sometimes is contained in more or less cryptic documentation for the library and in absence of such documentation through trial and error with lots of crashes. That's life of a C programmer and the Call Library Node can't avoid you from feeling that pain. It only is a means to let you interface to external code in shared libraries, not a guarantee that it won't crash if you do something wrong. And without additional knowledge from information contained in prosa text in the documentation for that API, most APIs, except the really trivial ones only using scalar parameters, are not possible to call reliable.
Any VI library created with the Import Library Wizard MUST be carefully reviewed by someone who knows about C programming and the peculiarities of the involved API, to be a really reliable way of calling that API. Anything else is more or less a random crash generator!
Personally I almost never use the Import Library Wizard. It doesn't add a lot since I have to review the code and quite frequently modify it anyhow significantly and the convenience of having at least the VIs itself created automatically is of limited value since I do not like the style of the VIs and the icons it generates.
09-30-2024 02:24 AM - edited 09-30-2024 02:30 AM
I am not blaming the wizzard, works ok some time. If the .dll does not have the function declarations in it, you are doomed anyway.
Seems our programmers are not really helpful either, so now have to struggle through VS as well. Suppose I post the solution later.
Have a look at the coolprop dll, a shining example how it could be done.
11-26-2024 04:14 PM
for future readers to have some starting point here some code bits
need to declare a header and have to declare the output variable as well. So Dll18 pretend its from the supplier
#pragma once
#ifdef dll18_EXPORTS
#define dll18_API __declspec(dllexport)
#else
#define dll18_API __declspec(dllimport)
#endif
//need to declare output variable as well for Labview to find it
extern "C" dll18_API void sumAB(double in1, double in2, double* out1);
the code for Dll18.dll
// dllmain.cpp : Defines the entry point for the DLL application.
#include "pch.h"
#include "dll18.h"
void sumAB(double in1, double in2, double* out1)
//need to declare output variable as well for Labview to find it
{
*out1 = in1 + in2;
}
wrappersum 2 is the interface to Labview, here the header file
#pragma once
#ifdef wrappersum2_EXPORTS
#define wrappersum2_API __declspec(dllexport)
#else
#define wrappersum2_API __declspec(dllimport)
#endif
extern "C" wrappersum2_API void LVsumAB(double LVin1, double LVin2, double* LVout1);
here the code. Supplier has all void functions, so the output needs to be a pointer
// dllmain.cpp : Defines the entry point for the DLL application.
#include "pch.h"
#include "DLL18.h"
#include "wrappersum2.h"
void LVsumAB(double LVin1, double LVin2, double* LVout1)
{
sumAB(LVin1, LVin2, LVout1);
}
so that compiled in Visual studio.
Then connecting to wrappersum2.dll found the variables ok, but there was a complaint about .dll missing, even though it was there. Then I connected Dll18.dll as friend and it went ok. Or better, the wizzard made anotherlibrary when I initially tested Dll18.dll. So I added this library as friend, then the error disappeared. Now I can run the vi for wrapperdll2 and get results for the calculation.
11-27-2024 02:56 AM - edited 11-27-2024 03:05 AM
Great that you found a solution and also reported about it. I would like to give some comments. They are not meant as critique but based on many years of my own experience trying to interface to external shared libraries in LabVIEW:
1) I do not understand the comment that you need to declare the output variable in order for LabVIEW to find it. If you want to return something to the caller you have of course have to return that to the caller, either trough the function return value or a reference parameter. That's completely independent of LabVIEW as caller. The only difference is that LabVIEW does not support arbitrary function return values. The only thing it supports are strings and scalar numeric. The reason for that is memory management (and in the case of a string, the function better returns a static allocated string that remains valid for a brief time after returning to the caller. LabVIEW is not going to try to deallocate it as it does not know how to do that). Anything else can not be properly managed without resorting to calling specific memory management routines and there are generally several different ones, under Windows you have about half a dozen memory managers to choose from and then the C runtime malloc. Except that your DLL may be compiled with a different C compiler (version) than the calling LabVIEW app and then malloc() in your DLL is not working on the same heap as free() in LabVIEW, as the C runtime is typically compiler specific. So if caller and callee do not absolute perfectly agree on which memory manager to use, you can not let one allocate memory and the other deallocate it. The basic principle in C programming therefore is:
- memory should be always allocated and deallocated by the same entity, be it caller or callee and never a shared responsibility for any specific C object (any memory block in C that stores some information)
- if you want to share management of C objects, callee and caller need to perfectly agree which family and incarnation of memory management calls they will use. This can be either that the caller (such as in LabVIEW) provides a specific set of memory manager functions to use for any objects received from LabVIEW or passed back to LabVIEW. The opposite can be that the callee provides a (set of) functions to manage the objects it allocates and returns to the caller. That way it is always guaranteed that allocation and deallocation happen from the same managed heap. This is also why .Net is called managed. It has very specific rules about who is responsible for allocation and deallocation of memory objects and what runtime functions are to be used to do that. LabVIEW in that sense is also managed but its management contract is substantially different to .Net (and predates .Net by at least 15 years).
2) The only difference in your original DLL and the LabVIEW specific wrapper is that your original DLL is compiled as C++ module and your wrapper declares the function explicitly as extern "C". So the wrapper only really serves as a means to export an explicitly C style function without C++ name mangling. That's not strictly necessary as the Call Library Node is perfectly able to let you select the name mangled function too. Yes the Import Library Wizard will most likely not like the C++ ism in the header file but to write a wrapper just to be able to let the Import Library Wizard import your functions is a very roundabout way to do business.
3) I have found that the use of pch.h is almost always causing more trouble than it solves. I always remove that from a project and disable precompiled header use in the project compiler settings. Unless you compile a project with several 100 or 1000 header files, it also doesn't really give you much of a measurable performance improvement.
4) As to your problem about the wrapper not finding the dependency DLL. Read up on the LoadLibrary() function, where Windows searches for DLLs when trying to resolve dependencies. There are only very specific locations it will search for and it is usually best to try to resolve to these locations or implement your own dependency loader in your own DLL (this is however a very advanced programming topic). I'm not sure what declaring a DLL as friend exactly does, but my guess is that it somehow adds a manifest to the DLL, that declares what other DLLs and/or their locations it wants to have found (maybe limited to its own directory). It's a possibility but another complication in the build tool chain that can eventually go wrong.
11-27-2024 03:32 PM - edited 11-27-2024 03:32 PM
this is just the start, somehow I have to involve classes etc. As in, provide a bunch of different values all over the place and the output luckily is an array of 30 floats.
So now I am on my own, have to learn C++ and its a total headache.
With the functions, usually its int sumAB(int a, int b). and when I call sumAB, that will be the result. But if you put that into Labview, you have 2 inputs but no outputs in the caller node. So instead I have to make it int sumAB(int a, int b, int out). But this is what I got given, supplier will not do something just for me
11-27-2024 04:21 PM
@Steffen01 wrote:
But if you put that into Labview, you have 2 inputs but no outputs in the caller node. So instead I have to make it int sumAB(int a, int b, int out). But this is what I got given, supplier will not do something just for me
Look again!