Jump to content

LV DLL creates mysterious DoubleArray class


Recommended Posts

So I created a DLL from a Labview VI that has a 2D array input (and some scalar inputs) and some 2D array outputs.  Labview creates a .h file with these lines

DoubleArray.PNG

And then it defines the 2D array arguments to my function as being of this type: "void __cdecl Linear_discrim_4dll(DoubleArray *dataObsFeat, int32_t grpAsz," etc etc.  Trouble is, I have no idea how to fill out this structure so that the DLL can use it.  Say for simplicity I had a 2 by 3 input called dataObsFeat with elements {1,2,3; 11,12,13}; how would I create the object with these values in C or C++ and pass it to the function?  I am a total C++ noob, in case it isn't obvious.

Link to post
On ‎11‎/‎04‎/‎2018 at 10:53 PM, torekp said:

So I created a DLL from a Labview VI that has a 2D array input (and some scalar inputs) and some 2D array outputs.  Labview creates a .h file with these lines

DoubleArray.PNG

And then it defines the 2D array arguments to my function as being of this type: "void __cdecl Linear_discrim_4dll(DoubleArray *dataObsFeat, int32_t grpAsz," etc etc.  Trouble is, I have no idea how to fill out this structure so that the DLL can use it.  Say for simplicity I had a 2 by 3 input called dataObsFeat with elements {1,2,3; 11,12,13}; how would I create the object with these values in C or C++ and pass it to the function?  I am a total C++ noob, in case it isn't obvious.

See the memory layout of Arrays at http://zone.ni.com/reference/en-XX/help/371361P-01/lvconcepts/how_labview_stores_data_in_memory/

 

If you create the 2-by-3 array in LabVIEW and pass it to your DLL, you can read it in C/C++like this:

void vi1(DoubleArray *array_fromLv)
{
    double cArray[2][3];
    cArray[0][0] = (*array_fromLv)->element[0];
    cArray[0][1] = (*array_fromLv)->element[1];
    cArray[0][2] = (*array_fromLv)->element[2];
    cArray[1][0] = (*array_fromLv)->element[3];
    cArray[1][1] = (*array_fromLv)->element[4];
    cArray[1][2] = (*array_fromLv)->element[5];

    // Do stuff...
}

 

To pass array data from the DLL to LabVIEW, the idea is to do the opposite:
void vi2(DoubleArray *array_toLv)
{
    double cArray[2][3];

    // Do stuff...

    (*array_toLv)->element)[0] = cArray[0][0];
    (*array_toLv)->element)[1] = cArray[0][1];
    (*array_toLv)->element)[2] = cArray[0][2];
    (*array_toLv)->element)[3] = cArray[1][0];
    (*array_toLv)->element)[4] = cArray[1][1];
    (*array_toLv)->element)[5] = cArray[1][2];
}

 

VERY IMPORTANT: Before your DLL writes any data, you must properly allocate the memory. There are 2 ways to do this:

  • Pre-allocate the array in LabVIEW, pass this array into the DLL, and let the DLL overwrite the array contents, OR
  • Call LabVIEW Manager functions (http://zone.ni.com/reference/en-XX/help/371361P-01/lvexcodeconcepts/labview_manager_routines/ ) to allocate or resize the array before writing the data. These functions are poorly-documented, however.
 

 

Edited by JKSH
Fix code errors
Link to post

Thanks!  Sorry, I wasn't clear.  I'm not trying to use a DLL in Labview.  I'm trying to use a DLL (that Labview created) in C++.  I read the first website on the "C Struct Hack" and tried to apply it to your advice, yielding this:

int i;       
int len = 2, len2 = 3;
int32_t datasz[2]={2,3};
double data1d[6] = { 1,2,3,11,12,13};
double aresult[2][2];
DoubleArray dataouta;
DoubleArray datain;

void viGet(DoubleArrayBase * result)
{
    for (i=0; i<4; i++) aresult[i/2][i%2] = (result->element);
}
void viSet(DoubleArrayBase * myArray)
{
    (myArray->dimSizes)[0] = 2;
    (myArray->dimSizes)[1] = 3;
    for (i=0; i<6; i++) (myArray->element) = data1d;
}

int main(int argc, char *argv[])
{
    viSet(datain);
    Linear_discrim_4dll(&datain,&dataouta,len,len2);
    viGet(dataouta);
)

and some printf statements.  This compiles (yay, a first!) but has a Fatal Runtime Error dereferencing a null pointer to datain, at the call to viSet.

Edited by torekp
Link to post

My apologies, I remembered wrongly and gave you wrong code. I've fixed my previous post now.

The syntax is funny because:

  • DoubleArrayBase is the struct itself.
  • DoubleArray is a pointer to a pointer to a DoubleArray struct (yes, you read that right)
On ‎12‎/‎04‎/‎2018 at 9:46 PM, torekp said:

I'm not trying to use a DLL in Labview.  I'm trying to use a DLL (that Labview created) in C++.

Everything in the first half of my previous post (up to and including the first block of code) still applies to C++ code that reads array data from the DLL.

C++ code that writes array data into LabVIEW is a bit more complex. Look in your LabVIEW-generated header file again: Do you see functions called AllocateDoubleArray() and DeAllocateDoubleArray()?

// In the LabVIEW-generated header, mydll.h
typedef struct {
	int32_t dimSizes[2];
	double element[1];
} DoubleArrayBase;
typedef DoubleArrayBase **DoubleArray;

DoubleArray __cdecl AllocateDoubleArray (int32_t *dimSizeArr);
MgErr __cdecl DeAllocateDoubleArray (DoubleArray *hdlPtr);


// In your code
#include "mydll.h"

int main()
{
	// Allocate and write the input array
	int32_t datasz[2] = {2, 3};
	DoubleArray arrayIn = AllocateDoubleArray(datasz);
	(*arrayIn)->element[0] = 1;
	(*arrayIn)->element[1] = 2;
	(*arrayIn)->element[2] = 3;
	(*arrayIn)->element[3] = 11;
	(*arrayIn)->element[4] = 12;
	(*arrayIn)->element[5] = 13;

	// Call your function
	DoubleArray arrayOut;
	Linear_discrim_4dll(&arrayIn, &arrayOut, 2, 3);

	// Extract data from the output array, ASSUMING the output is 2x2
	double cArray[2][2];
	cArray[0][0] = (*arrayOut)->element[0];
	cArray[0][1] = (*arrayOut)->element[1];
	cArray[1][0] = (*arrayOut)->element[2];
	cArray[1][1] = (*arrayOut)->element[3];

	// Free the input array's memory
	DeAllocateDoubleArray(&arrayIn);

	// ...
}

 

Edited by JKSH
  • Like 1
Link to post

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Similar Content

    • By Billy_G
      Hello, I wrote a LabVIEW program to communicate with a hardware sensor using vendor-provided LLB and a DLL files. The program runs fine on my workstation both from LabVIEW IDE and from a compiled executable. The problem starts when I copy the entire executable folder to a target host without a LabVIEW IDE (only with a runtime engine). The application opens with a broken Run arrow and a "missing external function" error message appears for every function call I made to the DLL (see attached).
      I have tested my application on 5 completely different Windows 10 computers managed by different people. On three of them with various versions of LabVIEW IDE my executable opened with a whole Run arrow and no error message. Two other machines previously had no LabVIEW, so I installed a Runtime Engine 2017f2 32-bit with default settings to match the version of my IDE. Both gave an identical error message.
      The DLL is always included in the application build. I have tried placing the DLL in every conceivable location on the target host: in the executable folder, in the /data folder, in the c:\Windows and system32 folders... I even created a full folder tree matching the location of the project on the developer workstation. Same error. When I intentionally hide the DLL, my executable prompts me to point to it upon being opened, and when I do, I get all the same error messages.
      Vendor documentation only asks to put the two files in the same folder. From programmer's manual: " The driver was written in LabWindows/CVI, version 4.0.1 and is contained in a dynamic link library which can be linked with a variety of programming languages." There is no vendor-provided support.
      One way I actually got rid of the error message was by editing every Call Library Function Node in every VI in the LLB to use relative path to DLL together with the Application Directory VI. However, I feel that there has got to be a better way to compile than by editing a vendor-provided library, especially since it works as-is on some computers. Can anyone suggest what it is?
      Thank you for your time!
       

    • By torekp
      DLL functions or shared variables?  Or something else?
      I have a Labview 2014-64 executable (or I can build a DLL) that runs one piece of equipment, the X-ray.  The other engineer has a large CVI Labwindows 2015 + MS Visual Studio 2012 (C++) executable that runs everything else.  I want the Labview code to be a slave of the CVI code, accepting commands to turn X-ray On or Off, reporting failures, and the like.  Translating the X-ray code into C++ would be possible in principle, but not fun.
      Shared variables look easy, but I'm kinda scared of them.  I would define all the shared variables in my LV code, since I'm more familiar with LV, then use them in both.  There's a thread in here called "Shared Variable Woes" so maybe I should be scared.  In the alternative, I tried building a proof-of-concept DLL in Labview, and calling its functions in CVI/C++, and it works, but it's kinda clunky.  (I'm attaching it below in case you want to play, or advise.)
      Your advice would be appreciated.
      XrayDLL.zip
    • By patufet_99
      To use a controller from LabVIEW I have to use some functions of a DLL.
      For one of the functions, according to the header file .h there is a structure data with parameters of different types that I have to pass to the dll. Some of the parameres are BYTE (1 Byte)  and WORD (2 Bytes).
      When compiling this kind of structure with Visual C++ and looking at it's size with "sizeof()" it seems to me that 4 Bytes variables have to start in a position multiple of 4. For example if there is a BYTE and then a DWORD, the 3 Bytes after the BYTE are ignored and the DWORD starts at Bytes 5 to 8.
      When defining a LabVIEW cluster to match the DLL structure, will LabVIEW do the same? If in my cluster there is a U8 variable and then a U32, will anyway the U8 take 4 bytes?
       
      Thank you.
    • By Fred chen
      Hi
       
      When I call the DLL, there is a structure:
      struct Signal { uint32 nStartBit; uint32 nLen; double nFactor; double nOffset; double nMin; double nMax; double nValue; uint64 nRawValue; bool is_signed; char unit[11]; char strName[66]; char strComment[201]; };  
       
      There is another  Message structure to the above Signal:
       
      struct Message { uint32 nSignalCount; uint32 nID; uint8 nExtend; uint32 nSize; Signal vSignals[513]; char strName[66]; char strComment[201]; }  
        The point is  Signal vSignals[513];
       
      I've tried to solve it like this,but the program will crash.
       
      How to create struct Message ,any good suggestions?  Thanks a lot.
       

      message.vi
    • By x y z
      Hello!

      I'd like to resize LStrHandle string in a C++ based DLL ... which is perfectly working on desktop Windows (ex.:Win7 32/64 bit) platform by include "extcode.h"  and linking "labviewv.lib", with calling "NumericArrayResize" function.
      BUT I'd like to do the same on Windows Embedded Compact 7.0 with ARM(Cortex-A8).
      When I build the DLL project on "Smart device / WindowsCE" platform it compiled successfully but the linker stopped because "NumericArrayResize" is unresolved symbol ... I think the reason is that the "labviewv.lib" generated for x86 architecture not for ARM.

      So my question is: Is there any libviewv.lib for ARM platform?
×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.