LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Issues with implementing a 32 resp. 64-bit dll to LabView 2013 13.0f2

Solved!
Go to solution

Dear Sirs and Madames,

 

I am trying to control a motorized device (MGZ30-MOT from thorlabs) with LabView 2013 (32-bit) , product version 13.0f2 on a Windows 7 64-bit PC. Unfortunately, there is no LabView support for the MGZ30-MOT, which means that there are no libraries or VIs for LabView.

 

First of all, I want to describe the component or rather its functionality. It is connected to the PC via USB and run by the Trinamic Virtual Serial Port Driver v5.0.2153.1. If you want to ,for instance, adjust the position of the device, there is a little program (written in C++ according to the vendor). There are 2 different folders for 32 and 64-bit, each containing an .exe, two .dll (one called ThemeControl.dll, which apparently does not contain the function described in the h.file, which I want to mention later on, and one called ThorZStepper.dll), a .lib-File (ThorZStepper.lib) and a .xml file (ZStepeprSettings.xml, which contains information about the baud-rate and the used COM-Port). Furthermore, there is a folder which contains the driver and a folder called "SDK", which contains subfolder with a .h-file, samples, and once more the files mentioned before.

To use your device, you have to alter the COM-ID in the .xml file and run the 64-bit .exe as an administrator.

 

First of all, I tried to use the VISA-USB-controls which worked fine with another device. Nevertheless, it did not work out for the MGZ30-MOT as I had no opportunity to get the necessary command-strings although I used a port-sniffer. The observed communication seems to be more complex than I expected and I was unable to extract the relevant information. To add, the device seems to be permanently communicating with the PC even if it is idle.

 

The next idea, which came to my mind, was to implement the .dll files. Therefore, I used the Import-function via Tools/Import/SharedLibrary and the only h-file I found in the folder and the dll-file which was located next to the .exe in the 64-bit folder. LabView created a .lvlib-file and I got access to some VIs, which were also described in the header-file. The problem is that I cannot execute theese VIs, because the .dll is 64-bit whereas LabView is only 32-bit (at least, LabView suggested that this is the error.

After that, I tried the same thing by using the same header-file (there is only one), but using the .dll located in the 32-bit folder. When I now attempt to execute the files, execution works but I get an error message "Call Library Function Node in ThorZStepper32.lvlib:Find Devices.vi". There are also some VIs, which do not generate this error, but also do not work.

 

My next try was to use the "Call Library Function Node" together with the documentation in the .h-file, but it did not work out. I am not sure if I messed up something or the 32-bit .dll simply won't work on the 64- bit OS. Could you please help me to use the "Call Library Function Node"  to investigate wether the 32-bit .dll is working properly?

 

Please find the h.-file, the documentation (html.zip) of the h.file and the VI, which should read the position, attached.

 

Best wishes and thank you in advance!

 

Download All
0 Kudos
Message 1 of 15
(3,216 Views)

Sorry for double-posting, but my addendum was too long.

 

PS: If you do not want to open the .zip archive, here is a copy of the .h-file. Nonetheless, it lacks documentation (I suppose).

 

/*! \file
*/

//ZStepper_SDK.h

extern "C"
{

/*! \enum Params Device parameter settings*/
    enum Params
    {
        PARAM_FIRST_PARAM,
        PARAM_DEVICE_TYPE=0,
        PARAM_Z_POS = 400,///<Absolute location for Z
        PARAM_Z_ZERO = 402,///<Set the current location to zero. The device will read zero for postion after this parameter is set
        PARAM_Z_STEPS_PER_MM = 403,///<Set the number of steps per millimeter. This is dependent on the know the stepper is connected to.
        PARAM_Z_VELOCITY = 404,///<The speed to move the stepper at
        PARAM_LAST_PARAM
    };

/*! \enum ParamType data of the parameter*/
    enum ParamType
    {
        TYPE_LONG,///<Parameter is of type integer
        TYPE_DOUBLE///<Parameter is of type double precision floating point
    };

/*! \enum DeviceType Type of the device returned by PARAM_DEVICE_TYPE*/
    enum DeviceType
    {
        DEVICE_TYPE_FIRST,
        STAGE_Z=0x10,
        DEVICE_TYPE_LAST
    };

/*! \enum StatusType return value for the StatusAcquisition status variable*/
    enum StatusType
    {
        STATUS_BUSY=0,///<Camera is busy capturing an image(s)
        STATUS_READY,///<Camera is idle or has completed capturing an image(s)
        STATUS_ERROR///<Error occuring during the capture. Error flag will persist until a new capture is setup.
    };


/*! \fn long FindDevices(long &DeviceCount)
    \brief Locates connected devices.
    \param DeviceCount The number of devices currently available
    \return If the function succeeds the return value is TRUE.     
*/
    long FindDevices(long &DeviceCount);


/*! \fn long SelectDevice(const long device)
    \brief Selects an available device
    \param device zero based index of a device
    \return If the function succeeds the return value is TRUE. All parameters and actions are directed the selected device.
*/      
long SelectDevice(const long Device);


/*! \fn long TeardownDevice
    \brief Release resources associated with the device before shutting down the application
    \return If the function succeeds the return value is TRUE and the device shutdown normally.
*/
long TeardownDevice();

/*! \fn long GetParamInfo(const long paramID, long &paramType, long &paramAvailable, long &paramReadOnly, double &paramMin, double &paramMax, double &paramDefault)
    \brief  Retrieve parameter information and capabilities
    \param paramID Unique identifier for the parameter to interrogate
    \param paramType The ParamType for the paramID
    \param paramAvailable Returns TRUE if the paramID is supported
    \param paramReadOnly Returns TRUE if the paramID can only be read
    \param paramMin Minimum value for the paramID
    \param paramMax Maximum value for the param ID
    \param paramDefault Recommended default for the paramID
    \return If the function succeeds the return value is TRUE.
*/
long GetParamInfo(const long paramID, long &paramType, long &paramAvailable, long &paramReadOnly, double &paramMin, double &paramMax, double &paramDefault);

/*! \fn long SetParam(const long paramID, const double param)
    \brief Sets a parameter value
    \param paramID Unique ID of the parameter to set.
    \param param Input value. If the Paramtype is long the data must be cast to type double.
    \return If the function succeeds the return value is TRUE.
    \example PositionTest.cpp
*/
long SetParam(const long paramID, const double param);

/*! \fn long GetParam(const long paramID, double &param)
    \brief Gets a parameter value
    \param paramID Unique ID of the parameter to retrieve
    \param param Current value of the parameter
    \return If the function succeeds the return value is TRUE.
    \example PositionTest.cpp
*/
long GetParam(const long paramID, double &param);


/*! \fn long PreflightPosition()
    \brief Using the current parameters arm the camera for a single/series capture
      \return If the function succeeds the return value is TRUE.
*/
long PreflightPosition();///<This submits the current parameters to the Device. There may be some first time latencey in settings parameters so its best to call this outside of the shutter control for image capture

/*! \fn long SetupPosition()
    \brief Using the current parameters the device is armed for the next capture
     \return If the function succeeds the return value is TRUE.
*/
long SetupPosition();///<This submits the parameters that can chage while the Device is active.


/*! \fn long StartPosition()
    \brief If not already started begin an image capture.
    \return If the function succeeds the return value is TRUE.
*/
long StartPosition();///<Begin the capture.

/*! \fn long StatusPosition(long &status)
    \brief Determine the capture status of the current image capture
    \param status Returns the status of the current capture. See StatusType.
    \return If the function succeeds the return value is TRUE.
*/
long StatusPosition(long &status);///<returns the status of the capture


/*! \fn long ReadPosition(DeviceType deviceType, double &pos)
    \brief Read the current location from the device. This may not equal the last position sent to the device if the device is moved manually.
    \return If the function succeeds the return value is TRUE.
*/
long ReadPosition(DeviceType deviceType, double &pos);


/*! \fn long PostflightPosition()
    \brief Releases any resources after a series of images have been captured
    \return If the function succeeds the return value is TRUE.    
*/
long PostflightPosition();


/*! \fn long GetLastErrorMsg(wchar_t * msg, long size)
    \brief Retrieve the last error message
    \param msg user allocated buffer for storing the error message
    \param size of the buffer (in characters) of the buffer provided
    \return If the function succeeds the return value is TRUE.    
*/
long GetLastErrorMsg(wchar_t *msg, long size);


}

0 Kudos
Message 2 of 15
(3,214 Views)

@MrKSE wrote:

 

First of all, I tried to use the VISA-USB-controls which worked fine with another device.  Nevertheless, it did not work out for the MGZ30-MOT


 


I don't understand what this means.

You are not able to use their program to control the device?

If so, I would most definitely make sure that is straighten out before doing anything else.

0 Kudos
Message 3 of 15
(3,201 Views)

Dear nyc,

 

probably I was not accurate enough. THEIR program, which is written in C++, works well.

 

What I wanted to say,is: I used the VISA-Control functions in LabView, where you can specify the port and send e.g. strings to the driver.  (I mean the functions described here:http://www.ni.com/white-paper/4478/en/).

This won't work for the MGZ30-MOT as I do not have the appropriate commands and so on.

 

I have to add, that I already know that one can write a wrapper .dll to make a 64-bit .dll accessible, but as I did not really unterstand how, i would prefer another solution. I have already read the article, which is often recommended in the forum (blog.mattmags.com/2007/06/30/accessing-32-bit-dlls-from-64-bit-code/).

0 Kudos
Message 4 of 15
(3,192 Views)

@MrKSE wrote:

 

I have to add, that I already know that one can write a wrapper .dll to make a 64-bit .dll accessible, but as I did not really unterstand how,


http://www.ni.com/white-paper/2818/en/

0 Kudos
Message 5 of 15
(3,180 Views)

Thank you again!

 

I already tried that, but failed. When I use the Import-Wizard with the 64-bit .dll I get VIs, which are not working due to the fact that the corresponding VI is a 64-bit VI, but LabView 32-bit.

But even when I use the 32-bit .dll, the VIs do not work. They execute, but nothing happens or an error occurs, depending on which VI I use. The error is not specified and says that it lies in the .dll.

 

I can copy the error code on Thursday and post it here, if this is useful.

 

 

0 Kudos
Message 6 of 15
(3,157 Views)

@MrKSE wrote:

Thank you again!

 

I already tried that, but failed. When I use the Import-Wizard with the 64-bit .dll I get VIs, which are not working due to the fact that the corresponding VI is a 64-bit VI, but LabView 32-bit.

But even when I use the 32-bit .dll, the VIs do not work. They execute, but nothing happens or an error occurs, depending on which VI I use. The error is not specified and says that it lies in the .dll.

 

I can copy the error code on Thursday and post it here, if this is useful.

 

 


Are these .NET DLLs?

 

Any more help, and I would need to paid for this project.

 

 

0 Kudos
Message 7 of 15
(3,152 Views)

Why do you think that this function declaration

 

long ReadPosition(DeviceType deviceType, double &pos);

 would result in a function that returns a string as first parameter? and then a String Handle!!!!! String (and Array) Handles are native LabVIEW datatypes that only DLLs can deal with that have been explicitedly written for use in LabVIEW by someone knowing exactly how this needs to be handled on the C side of the DLL.

 

Instead this function returns an int32,

has as first parameter an int32, or maybe an int8 passed by value

and last but not least a double passed by reference

 

For these three only the last is correct in your VI. And I'm sure all the other VI functions have similar problems.

 

Interfacing to DLLs is an art that requires some good C basic knowledge too.

Rolf Kalbermatter
My Blog
Message 8 of 15
(3,137 Views)

Hey rolfk,

 

I will change that, thank you.

 

I am not surre, if the other VIs have similiar problems, because the other VIs were automatically created by the Import Wizard whereas the posted VI was created by myself via the Call Library Function Node. The problem is that the Import Wizard finds the "ReadPosition" functions in the header-file but is unable to generate a VI for this particular function. However, the "ReadPosition"-function would be best to test if the VI works, since know the exact position through the shipped program. Furthermore, it is needed for our project.

 

@nyc: So, thank you that you helped for free 😉

 

 

0 Kudos
Message 9 of 15
(3,118 Views)

The import library wizard is no magic tool. It automates the creation of the VIs to wrap the DLL calls but by no means can guarantee to generate correct code for them. The C syntax used in the header file to declare the functions is notorously inadequate to really describe all aspects of a function call and its parameters. But it is the only thing that exists for function DLLs. So the import library wizard tries to do what it can and leaves the rest to the user.

For the ReadPosition() function this doesn't exactly apply, except that it probably stumbles over the definition of DeviceType which is an enum. C mandates no specific data size for enums. It only requires that the used datatype has to be an (unsigned) integer with a range big enough to represent the highest enum value. Some compilers will use the smallest possible integer which for DeviceType would be an (unsigned) char, since the biggest enum value is DEVICE_TYPE_LAST = 0x11 = 17, which fits easily into an 8 bit integer. Other compilers will use the default integer for the platform they compile to, which nowadays is usually 32 bits. But C doesn't prevent a compiler to choose an even smaller value than char for an enum (some embedded platforms might support nibbles (4 bits) for instance) or even a 64 bit integer.

 

Another issue that the import library wizard would need to have extra context information about the used compiler and its compile time settings is for instance when parameters consists of structs. How structs are layed out in memory is both compiler dependent and also from the compiler options used when the resulting DLL was compiled.

 

Last but not least any function having buffers as parameters (strings or pointers) requires extra context information that the header file is simply unable to provide, and the import library wizard therefore never can get right without extra user interaction in the VI afterwards. Extra complication here is that the C syntax is very ambigous about such parameters.

uint32_t *param

 could be a skalar 32 bit value passed by reference (pointer) or an (n dimensioanl) array of 32 bit values. No way to tell from the C syntax. You have to retrieve this information from the prosa text of the function description if it exists and sometimes even guess from the parameter name or the intended use for that function.

 

But parsing prosa text or guessing anything, are two things that automated tools are highly inadequate for.

Rolf Kalbermatter
My Blog
Message 10 of 15
(3,105 Views)