Jump to content

Calling a function from a dll with a pointer to a complex struct


Recommended Posts

Hello,

 

I am trying to call a function from a dll with a pointer to a complex struct. I have tried multiple ways to represent the string in the struct (see attached typedefs), but the output clusters from the dll call always has the same values as input (i.e the dll isn't updating the output values).  The ref ptr is based on an example from this link and I have attached a screenshot of my code for this case:

 

https://decibel.ni.com/content/docs/DOC-9079

 

Here is how the vendor defines the struct:

 

typedef struct {

  dword  passkey;  //password

  dword  request;  //0=readprop, 1=writeprop, 2=writerelinquish

  dword  deviceid;  //device instance

  dword  objectid;  //objectid

  dword  propid;  //property id

  dword  arrindex;  //array index

  dword  datatype;  //see simpletypes

  dword  value;

  dword  errorclass;

  dword  errorcode;

  dword  priority;  //1..16

  union {

  char  sval[1500];

  wchar_t  wval[1500/2];

  byte  bval[1500];

  BACnetDate dval;

  BACnetTime tval;

  datetime dtval;

  directaddr da;

  HWND  listbox;

  bufptr  buf;

  Range  rg;

  bdrCOV  cov;

  pxfer  *px;

  }aux;

  } bdrbag;

 

Here is how the vendor defines the struct in their vb example:

 

Type bdrbag

  passkey As Long 'password

  request As Long '0=readprop, 1=writeprop, 2=writeproprelinquish

  deviceid As Long   'device instance

  ObjectID As Long   'objectid

  propid As Long   'property id

  arrindex As Long   'array index

  datatype As Long   'see simpletypes

  value As Single

  errorclass As Long

  errorcode As Long

  priority As Long   '1..16

  sval(0 To 127) As Byte   'string value

End Type

 

Thanks,

 

Russell

 

TYPEDEF_BACNET_bdrbag_byte_cluster.ctl

TYPEDEF_BACNET_bdrbag.ctl

TYPEDEF_BACNET_bdrbag_ref_ptr.ctl

post-5002-0-85015700-1385148023.png

Link to comment

First thing that comes into my mind: struct alignment. LV clusters are byte aligned, the default alignment when working with Visual C++ is 8 bytes.

Your DLL vendor probably didn't change that, so you might need dummy elements in your cluster to ensure every data member starts at a multiple of 8 bytes.

Link to comment

Well the sval is not a pointer but a fixed size string or byte array and as such must be inlined in the structure. Your bdrbag_byte_cluster.ctl is as such the most accurate control to use. However it only matches the Visual Basic definition not the original C definition as in there it is really 1500 bytes long, not just 127. As long as you are sure that the underlying function is not trying to write past byte 127 there won't be a problem though.

All the other typedefs are not suited to resemble the C structure declaration in any way.

And candidus, alignment is not an issue for this particular structure. The alignment rule specifies that each structure element is aligned on the smaller value of either the integral element size or the alignment value. Here all numerics are 32 bit sized and align therefore automatically on their natural position and the string has an integral size of 1 byte and has therefore no alignment requirement.

Link to comment
Well the sval is not a pointer but a fixed size string or byte array and as such must be inlined in the structure. Your bdrbag_byte_cluster.ctl is as such the most accurate control to use. However it only matches the Visual Basic definition not the original C definition as in there it is really 1500 bytes long, not just 127. As long as you are sure that the underlying function is not trying to write past byte 127 there won't be a problem though.

All the other typedefs are not suited to resemble the C structure declaration in any way.

And candidus, alignment is not an issue for this particular structure. The alignment rule specifies that each structure element is aligned on the smaller value of either the integral element size or the alignment value. Here all numerics are 32 bit sized and align therefore automatically on their natural position and the string has an integral size of 1 byte and has therefore no alignment requirement.

 

Thanks Rolf,

 

I was thinking that cluster option was the most acccurate option, but it doesn't seem to return an updated value so there must be something else wrong with the dll or my interpretation of the struct.  I did have 1500 elements before, but seemed to make editing the cluster and VI in LV very slow and also caused the dll to error out at times. 

 

Thanks,

 

Russell 

Link to comment
Thanks Rolf,

 

I was thinking that cluster option was the most acccurate option, but it doesn't seem to return an updated value so there must be something else wrong with the dll or my interpretation of the struct.  I did have 1500 elements before, but seemed to make editing the cluster and VI in LV very slow and also caused the dll to error out at times. 

 

Thanks,

 

Russell 

 

Well, it is quite possible that the first section of the structure needs to be filled in with specific values that tell the function what to return in the union and for what resource (device, subunit, or whatever). So having even one value off might simply cause the function to error out. Have you checked the function return value itself to not indicate some error condition?

Link to comment
Well, it is quite possible that the first section of the structure needs to be filled in with specific values that tell the function what to return in the union and for what resource (device, subunit, or whatever). So having even one value off might simply cause the function to error out. Have you checked the function return value itself to not indicate some error condition?

 

Rolf,

 

I do sometimes get an error from the return value (which the vendor said happens at times). He suggested retrying until the return value is zero (i.e no error). When I do get a zero return value the output cluster has the same values as the input cluster (i.e the incorrect output values).  In terms of filling the specific values in the function I have copied the same input values that are used in the vendor's VB example executable.  The VB example executable executes properly, after several retries of course, and returns the output values I would expect. So I can't tell what I am doing differently from the VB code. I have web meeting with one of the vendor's support engineers on Monday so he can see exactly what is happening on my computer and hopefully determine what might be wrong.  Unfortunately he doesn't have LV at his site and isn't familiar so he can't test it at his site. 

 

Thanks again,

 

Russell

Link to comment

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 torekp
      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

      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.
    • 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
×
×
  • Create New...

Important Information

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