LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Trouble reading array from LabVIEW 7.1 ActiveX Server in VC++ 6

Using LabVIEW 7.1 and VC++ 6.0.

I'm having trouble reading data out of an array indicator via ActiveX. I have the VI compiled as an EXE, and I'm using C++ to read the value. I can read scalars just fine using the following code (with appropriate changes), and the array comes back with the proper type for an array of floats (VT_ARRAY | VT_R4), but the dimensions obtained from SafeArrayGetLBound and SafeArrayGetUBound are 0 and -1, respectively. SafeArrayGetDim returns 1. There are 50-ish elements in the array, and even direct access to them returns nonsense values. Is there some extra encoding going on between the LabVIEW array and the ActiveX SafeArray?

The app code (tabs have been eaten by the forum monster):

#include "stdafx.h"
#include "windows.h"
#include "stdio.h"
#include "conio.h"
#include
#include
#include
#import "MyApp.tlb"

#define VIPATH "C:\\LabVIEW\\MyApp\\DIAG\\AI Diagnostics.vi"

using namespace MyApp;


int main(int argc, char* argv[])
{
VARIANT sample;
int size = 0;
char Path[1000],Password[60] = "";


// generate a namespace declaration to and identify and assign a name to a declarative region.
// In this case we are assigning the LabVIEW.
_ApplicationPtr pLV;
VirtualInstrumentPtr pVI;


cout << "Pre-CoInitialize" << endl;
CoInitialize(NULL);
do
{
VariantInit(&sample);
cout << "Initialized, creating MyApp.Application instance" << endl;
pLV.CreateInstance("MyApp.Application");
if (pLV == NULL)
{
printf("LV must be running, exiting ...\n");
break;
}
cout << "Obtained App instance, creating VI instance" << endl;
pVI.CreateInstance("MyApp.VirtualInstrument");
cout << "Got VI instance" << endl;
strcpy(Path, VIPATH);

// assign an object reference to the pVI.
VARIANT_BOOL resvForCall = TRUE;
long options = 0x0;
cout << "Getting Ref to Desired VI" << endl;
pVI = pLV->GetVIReference(LPCTSTR(Path), LPCTSTR(Password), resvForCall, options);

// configure the VI to show its front panel on Call.
pVI->ShowFPOnCall = TRUE;

sample.vt = VT_ARRAY | VT_R4;

// Multiple reads to ensure that we don't get the default 0...
sample = pVI->GetControlValue("Count Data");
sample = pVI->GetControlValue("Count Data");

// Check dimensions (comes back as 1)
long cdim;
cdim = SafeArrayGetDim(sample.parray);
cout << "cdim = " << cdim << endl;

// Check variant type, should be VT_ARRAY | VT_R4
cout << "VT: " << sample.vt << endl;
cout << "VT_ARRAY | VT_R4: " << (VT_ARRAY | VT_R4) << endl;

// Check bounds before iterating over array to print values
HRESULT he;
bool goahead = true;
long lbound;
long ubound;
he = SafeArrayGetLBound(sample.parray, 1, &lbound);
if (FAILED(he)) {
cout << "Failed getting lower bound." << endl;
cout << "Bad Index? " << (DISP_E_BADINDEX == he) << endl;
goahead = false;
}
he = SafeArrayGetUBound(sample.parray, 1, &ubound);
if (FAILED(he)) {
cout << "Failed getting upper bound." << endl;
cout << "Bad Index? " << (DISP_E_BADINDEX == he) << endl;
goahead = false;
}

cout << "Lower Bound: " << lbound << endl;
cout << "Upper Bound: " << ubound << endl;

// Print each element
if (goahead) {
for (long i = lbound; i < ubound; i++) {
VARIANT val;
VariantInit(&val);
val.vt = VT_R4;
SafeArrayGetElement(sample.parray, &i, &val);
printf("%d The sample Value is %g\n", i, val.fltVal);
VariantClear(&val);
}
}

// Wait to quit
while( !kbhit() ) {
cout << "Hit any key to continue\r";
fflush( stdin );
}

pLV->AutomaticClose=0;
VariantClear(&sample);

} while (0);
CoUninitialize();
return (0);
}
0 Kudos
Message 1 of 7
(4,382 Views)
Ok, made a little progress. Since the VI's I'm wanting to extract data from are already running (or should be) when I need them, I'm not using the Run or Call methods. Just getting the reference and pulling the value out (for now). If the VI's not actually open, though, it won't work. Was able to get the right LBound and UBound from another VI, not compiled to an exe, but still couldn't get any data out of the array. If the array is of 0 size, the LBound is 0, and UBound is -1. Still don't understand why I can't read the value out of the array element, though.

Updated code fragment:

VARIANT val;
VariantInit(&val);
val.vt = VT_BSTR;
SafeArrayGetElement(sample.parray, &i, &val);
cout << "Element VT: " << val.vt << endl;

wprintf(L"(%d) The sample Value is %s\n", i, val.bstrVal);
VariantClear(&val);
0 Kudos
Message 2 of 7
(4,373 Views)
Is this an array of variants that you are passing? If not, I'm a bit confused why you are storing the array's elements as a variant datatype. As far as I am aware, the element should be stored as its appropriate datatype in C++. Also, have you checked out the return value of the SafeArrayGetElement function? It may give you some insight into what the problem is. Below is a list of possible return values and their corresponding meanings:

S_OK = Success
DISP_E_BADINDEX = The specified index is invalid.
E_INVALIDARG = One of the arguments is invalid.
E_OUTOFMEMORY = Memory could not be allocated for the element.

Regards,

Message Edited by AESulzer on 06-15-2005 03:00 PM

E. Sulzer
Applications Engineer
National Instruments
0 Kudos
Message 3 of 7
(4,369 Views)
Ok, I am getting an E_INVALIDARG, whether val is a BSTR, _bstr_t, char* or VARIANT. The parray should be right, as should i, so...what is the proper last argument? SafeArrayGetElement just says it's void* pvData, which...is just about useless (hooray for systems hungarian notation), and I guess the actual definition of the function is in a .dll somewhere, 'cause it's sure not in any .cpp files on my hard drive.
0 Kudos
Message 4 of 7
(4,362 Views)
The proper last argument depends on the datatype of the elements in the array. What is the datatype of the elements in your array? Also, are you saying that you are getting 0 and -1 as the bounds of 50-element safearray? If so, that is pretty peculiar.

Regards,
E. Sulzer
Applications Engineer
National Instruments
0 Kudos
Message 5 of 7
(4,349 Views)
Thanks for your help!

I have arrays of strings and arrays of doubles, neither of which work properly. For doubles I've tried variants (and setting my vt = VT_R8 before and after the attempted read), as well as simply passing it a pointer to a plain double. Strings, I've tried just about everything from a char* to a BSTR. I think I've got a way to make things work without passing arrays though, gonna treat it like an iterator. First call gets you the first item, subsequent calls get you the next items until the end, with a reset function of some sort. 'course, that only works if there's just the one other entity, but it'll do for now.
0 Kudos
Message 6 of 7
(4,346 Views)
Sorry about the long delay in my reply! Attached you will find an example that sets an array and then gets it back. The code of interest is in CArrayActivexLV7Dlg::0nButton1. Hope this helps!

Kind Regards,

Message Edited by AESulzer on 06-24-2005 03:27 PM

E. Sulzer
Applications Engineer
National Instruments
0 Kudos
Message 7 of 7
(4,319 Views)