08-19-2009 10:04 AM
I appreciate your help!
Question:
In my project, I need to deal with a hybrid programming of C++ and Labview. The C++ part has been encoded into a DLL, which aims to do a complex mathematics. The main function in the DLL has the following form:
float RateEqCalculate(class CLaserPulse *Pulse, class CMaterial *Material, class CThresh *ThreshPara, class CRateResults &r);
The four arguments are all of the class type. The first three arguments are used to input parameters to the function and the last one is used to record the process of computation. For example: class CLaserPulse is composed by several numerics and two functions as the following form:
class CLaserPulse
{
public:
float fDuration;float fWave;
float fNA;float fRefrIndex; // Refractive Index
float fAbsCoeff; // Absorption coefficient [1/m]CLaserPulse();
virtual ~CLaserPulse();
virtual double Shape(double dTime); // gives Temporal Shape
float SpotDiameter(); // Calculate Spotdiameter};
As in labview "class" cannot be accepted as an argument of the "Library Function Node" directly, a wrapper DLL is required to translate the "class" to the type labview can understand. The following link is a good illustration of this process. http://labviewwiki.org/DLL/shared_library Given the argument class CLaserPulse has been converted into the wrapper DLL by the method from the link, how can I later link this wrapper DLL to the target DLL. My understanding is like this:
Target DLL
float RateEqCalculate(
class CLaserPulse -> wrapper DLL .........linking......... class CLaserPulse,
class CMaterial -> wrapper DLL .........linking......... class CMaterial,
class CThresh -> wrapper DLL .........linking......... class CThresh ,
class CRateResults -> wrapper DLL .........linking......... class CRateResults );
Am I right? Four wrapper DLL to four class type arguments?
Many thanks!!!
08-25-2009 04:21 AM
Hi Kuo,
have to say that I have written a wrapper DLL, but I somehow used another way to do so (At least, it looks not so complicated like in the example :-)).
What you need:
- Your DLL (which includes the classes)
- A .lib file (should be automatically created if you build the upper DLL)
- the header file including the class definitions.
What you now have to do is: Write (in a new DLL, wrapper-DLL) a function that can accept all parameters you need for your classes, like fDuration, fWave, FNa and so on.. it's important to use only types that LabView can handle (like double, integer, string, ...)
Now, in your Wrapper, you have to create a member of the class you like to use, for example CLaserPulse. Fill your class with all parameters you need (passed from LabView). Add to your project (if you are using Microsoft Visual C++) the .lib and the .h of your other DLL and compile it. It should be linked to your DLL. By LabView, you can now access the wrapper DLL.
A short example (not sure about notation, not tried in C++):
DLL you like to access:
typedef struct //Complex Number Typedef, in header file
{
double real;
double imag;
} complex;
int calc(complex a) // Function in your DLL LabView can't handle because of datatype complex
{
//any code
}
WRAPPER-DLL:
int calc_wrap(double real, double imag)
{
//Build the complex datatype
complex temp;
temp.real=real;
temp.imag=imag;
return calc(temp); //pass variable temp to your DLL, calculate value and return it to labview
}
Hope this helps,
Greetings
Christian
08-25-2009 05:14 AM - edited 08-25-2009 05:16 AM
You do not necessarily have to create seperate wrappers for each class. A class is the same as in standard C a struct as far as memory layout is concerned. So your parameters are simply pointers to a struct. Now you can't access the members of that struct from within LabVIEW directly but you can treat the pointer to the class as a pointer sized integer when passing it to the Call Library Node.
What you will quite likely have to do is writing some constructor and destructor wrappers for each of your classes and if you need to access methods of those classes or variable members you will also have to write a method wrapper for each method you want to use as well as an accessor function for each variable member you want to be able to access. So likely your wrapper library will contain a lot more functions than just one for each class. In fact because of the constructor/deconstructor you will need, you will need at least 2 functions per class.
Rolf Kalbermatter
09-08-2009 02:44 AM
I just come back from my holidays. I really appreciate your suggestions!! I will try it.
09-08-2009 04:37 AM
I really like your penetrating explanation from the respects of memory layout.
I'll try it!
Thank you very much!
09-15-2009 09:55 AM - edited 09-15-2009 09:59 AM
Hello Rolf and Christian:
Thank you for your suggestions! I'm now working on it. I appreciate your continuous help!!
I'll briefly summarize my question here:
In the original DLL, which is compiled by VC++ 6.0 and named RateEquation.dll, three class types (CLaserPulse, CMaterial& CThresh) are inclueded to do parameter exchanges; one class type is designed to save the calculation results(CRateResults);one main function to do the calculation and save the results as following form:
float RateEqCalculate(class CLaserPulse*, class CMaterial*, class CThresh*, class CRateResults &r);
My question now is the initialization of the struct type and the communication between this type with labview.
I'll take class CMaterial as an example to show how I made it into wrapper DLL.Original class CMaterial is defined as following:
class CMaterial
{
public:
float AbsorberGap;
float BandGap;
float CollTime;
float ElDensity; float RefractiveIndex;
float AbsorptionCoeff;
float MoleculeMass;
float Density;
float HeatCapacity;
float HeatConductivity; float TAmbient;
CMaterial();
virtual ~CMaterial();
};
In a wrapper dll it's like this:
WrapperDll.h
extern "C" { /*using a C compiler*/ //Using a C compiler to write the wrapper DLL
#endif
struct RATEEQUATION_API CMaterial{
//Electronical properties
float AbsorberGap;
float BandGap;
float CollTime;
float ElDensity;
//Optical properties
float RefractiveIndex;
float AbsorptionCoeff;
//Other properties
float MoleculeMass;
float Density;
float HeatCapacity;
float HeatConductivity;
float TAmbient;
};
typedef struct CMaterial CMaterial; /* make the class opaque to the wrapper*/
RATEEQUATION_API CMaterial* creat_CMaterial(void);
RATEEQUATION_API void destroy_CMaterial(CMaterial* LV_ref);
#ifdef __cplusplus
}
#endif
WrapperDll.cpp
RATEEQUATION_API CMaterial* creat_CMaterial(void)
{
return new CMaterial();
}
RATEEQUATION_API void destroy_CMaterial(CMaterial* LV_ref)
{
delete LV_ref;
}
In function creat_CMaterial(), one can see the constructor of class CMaterial is called. As struct type CMaterial has the same memory layout as class type CMaterial, so it’s safe and possible to return a class CMaterial* to struct CMaterial* and it’s initialized by the default values in the class constructor. Now I’m confused by how one communicates between labview and struct CMaterial. For example, if I would like to change the parameter _CMaterial-> BandGap=6.5eV to 8eV. How to make it?My feeling is I need a cluster type from Labview as an input in the function creat_CMaterial:
CMaterial* creat_CMaterial(cluster_LV*)
Many thanks!
09-15-2009 10:21 AM
No, I do not think that creating a C struct and treating it as C++ object pointer is going to work. The C++ compiler is free to arrange the variables in the class to some extend and also will include at least one vtable immediately at the start of the memory that the class structure defines.
This is one of the reasons that you can not mix and match C++ libraries between compilers since they will arrange the class members often differently in memory therefore causing crashes if you call a C++ class from code compiled in compiler X while the class was implemented in compiler y.
Rolf Kalbermatter
09-16-2009 03:48 AM
Hello Rolf:
I think I made a mistake in the message. The same C++ compiler is used when treating C++ class type as a C struct . Using extern "C" in the code is to make the function calls C calls instead of C++ calls. Following is a link to explain the wrapper dll method. http://labviewwiki.org/DLL/shared_library
Thanks
Kuo
09-16-2009 10:23 AM
Even when using the same compiler you will not be able to treat a C++ class as C struct. The reason is that you can NOT easily deduce the exact memory layout from a C++ class declaration and therefore can't create a struct easily that would match that class layout.
The wiki page however is correct. Note that in there the object pointer is only referenced in the function wrappers, and while those functions should be prototyped with the extern C keyword to avoid name decoration and other nastyness, the code for those wrappers will be compiled by the C++ compiler so it knows how to access the class members properly.
Rolf Kalbermatter