07-04-2013 06:33 AM
@rolfk wrote:
Now you lost me!
You can't have code in your function that treats the incoming array in two different ways at the same time. The array is either a LabVIEW data handle or an array data pointer and trying to treat it in a different way than what you passed into it will surely cause strange effects including possible Access Violations.
I'm not planning to have both sets of code. I want to use it as an array data pointer. It wasn't working, so I tried accessing it as a LabVIEW data handle to see what I would get, just as an experiment. To my surprise, it worked all the time, no matter what settings I picked.
I thought that "array data pointer" would give me the data array without the dimSize. Since the knowledge base article suggested attaching a CIN and generating code I did that and copy and pasted it into our DLL in a debugging version. All that stuff is just test code to try to figure out what is going on.
And that is what my example shows to happen!
But it does not happen in my case.
OK, I see I wrote the answers backwards about these two bits of code. That is probably why I lost you! I will look at these two pieces of code again, and write the correct answers.
------------------------------------------------------------------
fprintf(pFile, "OK, using CIN generated structures: dimSize %d, with the following data: \n", pTD->dimSize); for (i = 0; i < numWords; i++) { fprintf(pFile, "%d: control--0x%x, data--0x%x \n", i, pTD->data[i].control, pTD->data[i].data); } fflush(pFile);
THIS produces valid data in the log file. (It shouldn't ?)
But does this part produce valid data in the log file? (it should)
pFile = fopen("LoadFIFOLog.txt", "w"); fprintf(pFile, "Starting Load FIFO with %d data words, data pointer 0x%x, with the following data: \n", numWords, data); for (i = 0; i < numWords; i++) { fprintf(pFile, "%d: control--0x%x, data--0x%x \n", i, data[i].control, data[i].data); } fflush(pFile);
THIS is the one that DOES NOT WORK. It gives me garbage.
You say that the first part I quoted does not work (which uses the LabVIEW data handle format) and the second always works irrespective of the configuration you use for the array parameter in the Call Library.
As I explained, I answered backwards before. Now I fixed it.
I suspect some mess up on your part. You can't have those two codes inside at the same time. Either you configure the parameter as array data pointer and use the code from my second quote (the first logging part in your source) or you configure it as array data handle and use the code in my first quoted source code (your second part in the logging). You can't have both active at the same time or you will at least access invalid memory if not worse and that could cause all kind of strange effects, including you seeing each time a valid logging and some garbage but the first time the first logging part creates the valid code and the second time the second one does.
OK, I don't plan to have them both. All the stuff in between TEMP and END TEMP comments is going away. That code is my attempt to figure out what is going on.
You could declare your wrapper as const. Passing a const to a non-const declared value is valid, the opposite not.
I think this time you got it backwards. You can pass a non-const variable into a function with a const parameter, but not the other way around.
Of course it doesn't really buy you anything as the underlaying DLL developer could still decide he wants to update the data in the array at some point and LabVIEW believing it is safe to reuse the array elsewhere could then be tripped by this as it might suddenly use the modified array, believing it should be still the original array as when it got passed to your CLN.
07-04-2013 06:34 AM
Would this work differently in LabVIEW and LabVIEW Realtime? We use the same VIs for both (most of the VIs in our library).
I am currently running it on LabVIEW RT.
Batya
07-04-2013 06:49 AM
Apparently there is a difference in LVRT, as I just created a project based on your example (I compiled the dll in LabWindows/CVI and called it StructureArrayRT.dll, and changed your VI to look for the DLL with this name, and I stuck the VI into a new Realtime project to run it on the target). Anyway, when I run it, the realtime target either gives me a turquoise screen with a bunch of errors or the realtime target simply resets.
Heellllppp!! ![]()
07-04-2013 09:22 AM
Could be a bug in LabVIEW RT. If that is the case then you need to file a support request at NI. However the only short term solution would be to pass the data in LabVIEW native format and do the translation in your wrapper. Not really that a big task actually, as all you need to do is changing the configuration of the CLN, as well as the declaration of the function and then passing the right values to your internal DLL.
Basically:
int32_t Load_Transmit_FIFO_RTx(uint32_t handle, uint16_t channel,
int32_t FIFOnumber, void data[], int32_t numWords, int32_t *actualLoaded,
int32_t *actualStartIndex)
{
/* Insert code here */
would get:
typedef struct {
int32_t control;
int32_t data;
} TD2;
typedef struct {
int32_t dimSize;
TD2 data[1];
} TD1;
typedef TD1 **TD1Hdl;
#include "lv_epilog.h"
int32_t Load_Transmit_FIFO_RTx(uint32_t handle, uint16_t channel,
int32_t FIFOnumber, TD1Hdl *data, int32_t *actualLoaded,
int32_t *actualStartIndex);
{
if (!*data)
return mgArgErr; // Empty array passed in
int32_t numWords = (**data)->dimSize;
void data[] = (**data)->data;
/* Insert code here */
}
07-07-2013 01:12 AM
Yes, since I have a wrapper I can do that. Clearly there is a problem because not always does one have the option of changing the DLL code.
The problem that I have is that the wrapper DLL is the same for both our LVRT and our regular LabVIEW products. The only thing I can think of is to pass a void pointer, somehow know inside the DLL whether I was called from LVRT or LabVIEW, and then cast accordingly. Ugly, but it should work. But is there some simple way to know that I was called from LVRT?
Thank you.
Batya
07-07-2013 06:52 AM
Curiouser and curiouser...
Now I took your (Rolfk)'s example VI as it is, but compiled the DLL in LabWindows/CVI instead of Visual Studio and pointed the VI to that DLL (I called it StructureArrayRT.dll).
I ran it in LabVIEW without LVRT. It crashed.
How could the compiler with which I compile the DLL affect how LabVIEW passes the array to it?!?
Thank you.
Batya
07-07-2013 10:44 AM
@BPerlman wrote:
Yes, since I have a wrapper I can do that. Clearly there is a problem because not always does one have the option of changing the DLL code.
The problem that I have is that the wrapper DLL is the same for both our LVRT and our regular LabVIEW products. The only thing I can think of is to pass a void pointer, somehow know inside the DLL whether I was called from LVRT or LabVIEW, and then cast accordingly. Ugly, but it should work. But is there some simple way to know that I was called from LVRT?
Thank you.
Batya
You can use the same code on both platforms. Just pass the LabVIEW native Data handle to your wrapper DLL and do the translation as I explained in there to pass the actual array data pointer to your internal dll, and do this on LabVIEW desktop and LabVIEW RT. Since the Call Library Node seems to pass the native data type correctly on both platforms that should work. According to your claims it's only the array data pointer that does not work as expected on LabVIEW RT. So by avoiding it and doing the case which works on RT also in your desktop version, you should be clear.
Basically that little code change I showed you for your wrapper DLL is all the Call Library node really does itself when you configure the array as passed as array data pointer. No real magic, just some convinience.
07-07-2013 10:48 AM - edited 07-07-2013 10:49 AM
@BPerlman wrote:
Curiouser and curiouser...
Now I took your (Rolfk)'s example VI as it is, but compiled the DLL in LabWindows/CVI instead of Visual Studio and pointed the VI to that DLL (I called it StructureArrayRT.dll).
I ran it in LabVIEW without LVRT. It crashed.
How could the compiler with which I compile the DLL affect how LabVIEW passes the array to it?!?
Thank you.
Batya
Are you sure your CVI compiler is not set to use stdcall calling convention by default? This setting can be set per function export through __cdecl or __stdcall declarations but can usually also be set globally as compiler option. Visual C uses __cdecl as default and I therefore didn't explicitedly add __cdecl to the function exports.
Would usually do that, but this was a quick and dirty test example.
07-08-2013 03:41 AM
Duh! I should have remembered that. Yes, the problem was the calling convention.
Now all the little examples I made based on yours, work.
So why doesn't my original VI?
Hmmmm.......still a mystery.
Batya
07-09-2013 02:43 PM
Im sorry to hear you are still having issues getting your original VI to work.
Have you tried integrating your dll code into the example one function at a time?
You can also try rebuilding your VI based on rolfk's example.