LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Complex cluster in calling dll

Solved!
Go to solution

Hi there:

 

I'm calling a function in a C dll, which have a complex structure input.

Function called like below:

=========================================================================

CanSendMsg(unsigned short wCard, unsigned short wBus, tCanMsg *hCanMsg);  

=========================================================================

My block point is " tCanMsg *hCanMsg " structure input, it is a complex structure with some enums and data type, when I run this function, dll alwalys return "error parameters", 

 

Below is the definition of " tCanMsg " and some enum type, the red part below are most speculation.

==========================================================================

typedef struct
{
unsigned short wHandleMsg;
unsigned long dwIdent;
tCanTypeId eTypeId;
unsigned long dwMask; 
tCanService eService;
unsigned long lPeriod;
unsigned long dwReserved1;
unsigned long dwReserved2; 
unsigned short wDataLen; 
unsigned char bData[CAN_MAX_DATA];
} tCanMsg;

 

typedef enum
{
CAN_ID_STD = 0, 
CAN_ID_XTD = 1 
} tCanTypeId;

 

typedef enum
{
CAN_SVC_TRANSMIT_DATA = 0, 
CAN_SVC_RECEIVE_DATA = 1, 
CAN_SVC_TRANSMIT_RTR = 2,
CAN_SVC_RECEIVE_RTR = 3
} tCanService;

==========================================================

Attached zip file is the vi I program and dll need calling, pls help to check the issues, many thanks

 

0 Kudos
Message 1 of 12
(4,482 Views)

Sorry, I forgot to update source vi to lv 8.6 version, post before source code is labview 2013 version

0 Kudos
Message 2 of 12
(4,446 Views)

There are a couple of issues. First, the bData field needs to be a cluster in LabVIEW, not an array, containing CAN_MAX_DATA elements.

 

The Enum elements in the struct are likely ints, meaning they should be 32-bit values. It would be a good idea to create LabVIEW enumerations (as type definitions) that match the values in the header file.

 

Most likely you need to add padding elements to get the correct alignment, unless the header file for the DLL specifies a non-standard packing. It looks to me like you need to add a U16 element between wHandleMsg and dwIdent to align dwIdent correctly.

0 Kudos
Message 3 of 12
(4,427 Views)

Thank for your advice, nathand

 

One defininition I missed for "unsigned char   bData[CAN_MAX_DATA]" like below:   

================================

#define CAN_MAX_DATA         8

================================

 

so this mean bData is:

==============================

unsigned char   bData[8]

==============================

Could you show a detailed method that how to config a cluster to fulfill bData[8]?

 

Regarding "U16 element between wHandleMsg and dwIdent", could you explain more detailedly why? because my vi followed  the sequency yet that structure defined in the source code,  like below:

================================

typedef struct
{
unsigned short wHandleMsg;

unsigned short ???
unsigned long dwIdent;

================================

Does the NI have a document that define the method how to align the elements while using cluster in DLL calling? 

 

thanks

0 Kudos
Message 4 of 12
(4,417 Views)
Solution
Accepted by topic author XiaomingSu

@XiaomingSu wrote:
Could you show a detailed method that how to config a cluster to fulfill bData[8]?

Create a cluster with 8 U8 elements. Or, place an array constant on your block diagram, with U8 elements. Wire it to "Array to Cluster". Set the cluster size to 8 elements. Create a constant from the cluster output, and put that cluster inside your larger cluster. Now you have a cluster of 8 elements that corresponds to the bData struct element.

 


@XiaomingSu wrote:
Does the NI have a document that define the method how to align the elements while using cluster in DLL calling?

Clusters in LabVIEW Do Not Line Up With Structures in Visual C++

By default, C compilers align the elements of structs, whereas LabVIEW packs cluster elements as tightly as possible. To make LabVIEW match C, you need to add "packing" elements to your cluster to line up the cluster elements correctly with the struct elements.  An internet search for "struct alignment" will provide lots of results, for example http://www.catb.org/esr/structure-packing/ and https://en.wikipedia.org/wiki/Data_structure_alignment. You can also find examples of calling a DLL function with a struct as a parameter elsewhere on this forum with some searching.

0 Kudos
Message 5 of 12
(4,405 Views)

Realy appreciate your perfect answer.

 

Still have a question, why use a cluster not char array for inputting string while calling dll?

 

 

0 Kudos
Message 6 of 12
(4,383 Views)
Solution
Accepted by topic author XiaomingSu

Let's say you have two structs in C:

struct a {
int num;
char *str;
}

struct b {
int num;
char str[50];
}

Are these the same thing? No. The size of struct a is the size of an int plus the size of a pointer. The size of struct b is the size of an int plus 50 bytes. If you pass a pointer to struct a, to a function that wants struct b, it won't work properly.

 

Same thing with LabVIEW clusters. When you make bData a cluster of 8 elements, it has a fixed size and the data it contains is included inline in the cluster. If you make it a string, the size isn't known so the overall cluster instead contains a pointer to the string data somewhere else. You might find "How LabVIEW Stores Data in Memory" helpful.

 

Important note: a LabVIEW string or array, when embedded in a cluster, is not the same as a C array or string embedded in a struct. If you were trying to call a function that uses "struct a" from my example, it would not work to create a cluster containing an int and a string, or an int and an array of U8, because LabVIEW stores additional information (about dimensions or string length) as part of the array or string. For passing a string or an array on its own, LabVIEW will do the appropriate translation.

0 Kudos
Message 7 of 12
(4,377 Views)

Many thanks for your brilliant explain,  now I understand truely how the labview to run cluster in Dll calling.

 

The dll I calling it works right now.Smiley LOL

 

I also have a new idea may bother you again, nathand.

 

What type do I have to set if the input is char str[]? such as char str[16], it have define a array with static size.

 

Use string type and C pointer method ? Or is it a array of U8 int?

 

0 Kudos
Message 8 of 12
(4,355 Views)

XiaomingSu wrote:

What type do I have to set if the input is char str[]? such as char str[16], it have define a array with static size.

 

Use string type and C pointer method ? Or is it a array of U8 int?


Assuming the string is a parameter on its own, and not part of a struct, you can use either a LabVIEW string or an array of U8, since in both cases it will be passed as a pointer to an array of bytes. You should initialize the string or array to the correct length before passing it to the DLL. If you're working with an actual C string, don't forget that it should be null-terminated.

0 Kudos
Message 9 of 12
(4,329 Views)

Are you complete this problem?
can you share the succeed solution with me?

I have a dll,Function parameter define as follow

 

typedef struct
{
uint32_t LocId;
uint32_t EESize;

uint8_t SerialNumber[64];
uint8_t Description[4096];
const char* FileInfo;
} IoData_t;

 

What can I do to solve this problem,in labview call this dll's Function

Looking forward to your advice, thanks!!!!

0 Kudos
Message 10 of 12
(3,845 Views)