From 04:00 PM CDT – 08:00 PM CDT (09:00 PM UTC – 01:00 AM UTC) Tuesday, April 16, ni.com will undergo system upgrades that may result in temporary service interruption.

We appreciate your patience as we improve our online experience.

NI TestStand

cancel
Showing results for 
Search instead for 
Did you mean: 

How to access the value of a .NET Object Reference Variable

Solved!
Go to solution

I am running a TestStand sequence file from a c# wrapper and want to exchange parameters / results between the wrapper and the sequence. I use the FileGlobals to do this. For the built-in types (string/number/boolian) this works fine, however I also need non-generic types, e.g. Bitmap images. Those would be stored like this:

 Sequence.jpg

 

To access the variable content I'm using the following code in my wrapper:

            PropertyObject runtimeObject = sequenceGlobals.GetPropertyObject(propertyPath, 0);
            switch (Type)
            {
                case DataType.TypeBoolean:
                    return runtimeObject.GetValBoolean("", 0);
                case DataType.TypeDouble:
                    return runtimeObject.GetValNumber("", 0);
                case DataType.TypeInt64:
                    return runtimeObject.GetValInteger64("", 0);
                case DataType.TypeUInt64:
                    return runtimeObject.GetValUnsignedInteger64("", 0);
                case DataType.TypeString:
                    return runtimeObject.GetValString("", 0);
                case DataType.TypeObject:
                    //what do I do here to get the content of the .NET Object???

Thanks for the support

0 Kudos
Message 1 of 12
(3,462 Views)

GetValIDispatch("", 0)

jigg
CTA, CLA
testeract.com
~Will work for kudos and/or BBQ~
0 Kudos
Message 2 of 12
(3,436 Views)
Solution
Accepted by topic author Michael_Volk

GetValInterface will also work and is a bit more generic than using IDispatch since it doesn't require the object have an IDispatch interface, though I think all .NET objects probably do.

0 Kudos
Message 3 of 12
(3,428 Views)

Tried both, "GetValInterface" and "GetValIDispatch". Both works, however I don't know how to handle the resulting object. How do I convert the result of the GetValIDispatch("", 0) back to the underlying .NET object, i.e. the System.Drawing.Bitmap in my example. Note that the type can vary and I don't want to restrict my code to Bitmaps.

A bit of sample code using either of the two calls (GetValInterface or GetValIDispatch) would be really helpful.

0 Kudos
Message 4 of 12
(3,408 Views)
Solution
Accepted by topic author Michael_Volk

So I've never actually done what you are doing in .NET but my guess is you can just typecast it to the .NET type?  Have you tried that? Ultimately I think it is just a .NET reference.

jigg
CTA, CLA
testeract.com
~Will work for kudos and/or BBQ~
0 Kudos
Message 5 of 12
(3,396 Views)

You can use either a cast or the "as" operator.

0 Kudos
Message 6 of 12
(3,383 Views)

Unfortunately, type casting works somehow, but not completely.

For example If I typecast my GetValInterface object to a

Object val = runtimeObject.GetValInterface("", 0);
System.Drawing.Bitmap bmp = (System.Drawing.Bitmap)val

I can save this Bitmap to a file which works fine

bmp.Save(@"c:\temp\test2.bmp");

However I can't serialise the Bitmap (or any other type .NET type that is ISerializable). Same if I try to clone it. Always get exceptions indicating that the type is not quite correct.

Seems more a problem of my lack of understanding .NET Reflection rather than TestStand. So thanks for all the help which got me at least 90% to my solution.

0 Kudos
Message 7 of 12
(3,371 Views)

I suspect this is a separate issue from the GetValInterface call and cast.

 

1) Can you post the exact error message here?

2) How did the object get into the object reference variable? From a .NET adapter call, or programmatically from code? If from code, was that code called by the .NET adapter, UI, or elsewhere? (This can effect which appdomain the object resides in)

3) Does serialization work from the location in which you originally created the object or do you get the same error there?

0 Kudos
Message 8 of 12
(3,356 Views)

Ok, tried to nail down the problem as much as i can. My Teststand sequence consists of two .NET Action calls
1. Load Bitmap via call to System.Drawing.Bitmap(string filename):

Zwischenablage01.jpg

2. Serialize Bitmap using a simple self made static function posted below:

Zwischenablage02.jpg

The function used to serialize an object is this:

public static class Serializer
{
public static string Serialize(object obj)
{
SoapFormatter soapFormat = new SoapFormatter();
MemoryStream myStream = new MemoryStream();
string reqString;
soapFormat.Serialize(myStream, obj); // Line 119
myStream.Position = 0;
using (StreamReader sr = new StreamReader(myStream))
{
reqString = sr.ReadToEnd();
}
return reqString;
}
}

From within Teststand this works like a charm. Now I execute the very same same sequence file from my wrapper using the ApplicationManager. After the execution has finished, I'm retrieving the sequence globlas and evaluate those of type "Object Reference" like this:

PropertyObject runtimeObject = SequenceGlobals.GetPropertyObject(propertyPath, 0);
dynamic value = runtimeObject.GetValVariant("", 0);
string result = "";
try
{
  result = TS_Helper.Serializer.Serialize(value);             // Line 169
}
catch (Exception e)
{
  Logger.Error(e);
  result = value.GetType().toString();
}
return result;

and this code throws the following exception:

System.Runtime.Serialization.SerializationException: Der Typ "System.Runtime.Serialization.SerializationInfo" in Assembly "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" ist nicht als serialisierbar gekennzeichnet.

Server stack trace: 
   bei System.Runtime.Serialization.FormatterServices.InternalGetSerializableMembers(RuntimeType type)
   bei System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
   bei System.Runtime.Serialization.FormatterServices.GetSerializableMembers(Type type, StreamingContext context)
   bei System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitMemberInfo()
   bei System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitSerialize(Object obj, ISurrogateSelector surrogateSelector, StreamingContext context, SerObjectInfoInit serObjectInfoInit, IFormatterConverter converter, ObjectWriter objectWriter, SerializationBinder binder)
   bei System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.Serialize(Object obj, ISurrogateSelector surrogateSelector, StreamingContext context, SerObjectInfoInit serObjectInfoInit, IFormatterConverter converter, ObjectWriter objectWriter, SerializationBinder binder)
   bei System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Serialize(Object graph, Header[] inHeaders, __BinaryWriter serWriter, Boolean fCheck)
   bei System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(Stream serializationStream, Object graph, Header[] headers, Boolean fCheck)
   bei System.Runtime.Remoting.Channels.CrossAppDomainSerializer.SerializeMessageParts(ArrayList argsToSerialize)
   bei System.Runtime.Remoting.Messaging.SmuggledMethodCallMessage..ctor(IMethodCallMessage mcm)
   bei System.Runtime.Remoting.Messaging.SmuggledMethodCallMessage.SmuggleIfPossible(IMessage msg)
   bei System.Runtime.Remoting.Channels.CrossAppDomainSink.SyncProcessMessage(IMessage reqMsg)

Exception rethrown at [0]: 
   bei System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
   bei System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
   bei System.Runtime.Serialization.ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
   bei System.Runtime.Serialization.Formatters.Soap.WriteObjectInfo.InitSerialize(Object obj, ISurrogateSelector surrogateSelector, StreamingContext context, SerObjectInfoInit serObjectInfoInit, IFormatterConverter converter, SoapAttributeInfo attributeInfo, ObjectWriter objectWriter)
   bei System.Runtime.Serialization.Formatters.Soap.WriteObjectInfo.Serialize(Object obj, ISurrogateSelector surrogateSelector, StreamingContext context, SerObjectInfoInit serObjectInfoInit, IFormatterConverter converter, SoapAttributeInfo attributeInfo, ObjectWriter objectWriter)
   bei System.Runtime.Serialization.Formatters.Soap.ObjectWriter.Serialize(Object graph, Header[] inHeaders, SoapWriter serWriter)
   bei System.Runtime.Serialization.Formatters.Soap.SoapFormatter.Serialize(Stream serializationStream, Object graph, Header[] headers)
   bei TS_Helper.Serializer.Serialize(Object obj) in C:\develop\TS_Helper\TS_Helper_Library\OPCUA_ResultRecord.cs:Zeile 119.
   bei System.Dynamic.UpdateDelegates.UpdateAndExecute2[T0,T1,TRet](CallSite site, T0 arg0, T1 arg1)
   bei VMB100.DynamicOPCTag.getTeststandValue(PropertyObject sequenceGlobals, String lookupString) in C:\develop\VMB100 - v0.3\VMB100\DynamicOPCTag.cs:Zeile 169.

 

0 Kudos
Message 9 of 12
(3,340 Views)

I'm a bit confused what you mean by this code:

 

dynamic value = runtimeObject.GetValVariant("", 0);

 

I thought you were using GetValInterface and casting to the C# data type (Bitmap in this case).

 

It does look like you are passing the object across appdomains, which makes things more complicated, but should work if the class is serializable which Bitmap should be. Are you sure "value" in the code above is really the Bitmap class object? Why does the code not look like this?:

 

Birmap value = (Bitmap) runtimeObject.GetValInterface("", 0);

 

Also, if possible, you might be better off serializing the bitmap within the appdomain it was created in and just passing the serialized strings across appdomains rather than passing the bitmap object itself.

 

-Doug

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