Professional OPC
Development Tools

logos

Online Forums

Technical support is provided through Support Forums below. Anybody can view them; you need to Register/Login to our site (see links in upper right corner) in order to Post questions. You do not have to be a licensed user of our product.

Please read Rules for forum posts before reporting your issue or asking a question. OPC Labs team is actively monitoring the forums, and replies as soon as possible. Various technical information can also be found in our Knowledge Base. For your convenience, we have also assembled a Frequently Asked Questions page.

Do not use the Contact page for technical issues.

Writing ByteString

More
10 Jul 2019 09:13 #7509 by federica
Replied by federica on topic Writing ByteString
Thank you very much for your support.

I solved my problem with the following cast:
variant_t vArray;
vArray.ChangeType(VT_ARRAY | VT_UI1, &output);

Please Log in or Create an account to join the conversation.

More
19 Jun 2019 13:49 #7448 by support
Replied by support on topic Writing ByteString
Hello.

You can read the DataType attribute of the node to obtain its data type. What you get a back is a node ID of the data type; this need to be compared with the "standard" node IDS for various types, as defined in the OPC UA specification. An example of reading the data type attibute (unfortunately for .NET only) is here: opclabs.doc-that.com/files/onlinedocs/QuickOpc/Latest/User%2...%20of%20a%20single%20node.html .

I do not quite understand the part about ChangeType. First of all, I think that changing type to VT_CARRAY or VT_SAFEARRAY is pointless, they are special values not meant for user code. And, VT_ARRAY is a bit that needs to OR-ed with some other scalar VT_xxxx in order to make sense. Second, in your two-line example, the contents of vString is an empty variant (VT_EMPTY), so no wonder that its type cannot be changed. You can use ChangeType on variants for e.g. converting numbers to string or converting between integer types (if the value fits into the target range) etc., but do not expect it to convert between strings and arrays and similar things.

Regards

Please Log in or Create an account to join the conversation.

More
18 Jun 2019 13:44 #7444 by federica
Replied by federica on topic Writing ByteString
I found a similar solution:
void WriteValue::ByteString() {
  CoInitializeEx(NULL, COINIT_MULTITHREADED);
 
  _bstr_t serverParam(_T("opc.tcp://localhost:4840"));
  _bstr_t valueParam(_T("ns=2;s=VARIABLE")); 
 
  _EasyUAClientPtr ClientPtr(__uuidof(EasyUAClient));
  // Obtain attribute data. By default, the Value attribute of a node will be read.
  try{
    // Insert Content into the array: saByteArray
     CString writeValue (_T("TEST"));
     CComSafeArray <BYTE> saByteArray(256);
    int nRealLength = writeValue.GetLength();
    saByteArray.Resize(nRealLength);
 
    for(int i = 0; i < min(nRealLength, 256); i++) {
        saByteArray.SetAt(i, writeValue.GetAt(i));
    }
 
    CComVariant varArrayWrapper (saByteArray);
 
    _UAWriteValueArgumentsPtr WriteValueArguments1Ptr(_uuidof(UAWriteValueArguments));
    WriteValueArguments1Ptr->EndpointDescriptor->UrlString = serverParam;
    WriteValueArguments1Ptr->NodeDescriptor->NodeId->ExpandedText = valueParam;
    WriteValueArguments1Ptr->Value = varArrayWrapper;
 
    CComSafeArray<VARIANT> arguments(1);
    arguments.SetAt(0, _variant_t((IDispatch*)WriteValueArguments1Ptr));
 
    // Obtain values. By default, the Value attributes of the nodes will be Write.
    LPSAFEARRAY pArguments = arguments.Detach();
    CComSafeArray<VARIANT> results;
    results.Attach(ClientPtr->WriteMultipleValues(&pArguments));
    arguments.Attach(pArguments);
 
    // Display results
    for (int i = results.GetLowerBound(); i <= results.GetUpperBound(); i++) {
        _UAWriteResultPtr ResultPtr = results[i];
 
        if (ResultPtr->Succeeded)
            _tprintf(_T("Result %d success\n"), i);
        else {
            CString msg;
            msg.Format(_T("Result %d: %s\n"), i, CW2T(ResultPtr->Exception->GetBaseException()->Message));
            AfxMessageBox(msg);
        }
    }
 
    SAFEARRAY* pResults = results.Detach();
    pArguments = arguments.Detach();
 
    SafeArrayDestroyData(pArguments);
    SafeArrayDestroyData(pResults);
 
    SafeArrayDestroy(pArguments);
    SafeArrayDestroy(pResults);
 
    arguments.Destroy();
    results.Destroy();
 
    pArguments = NULL;
    pResults = NULL;
    }
    catch (const _com_error& e){
    CString desc( (LPCTSTR) e.Description());
    CString errorMessage(e.ErrorMessage());
  }
 
  // Release all interface pointers BEFORE calling CoUninitialize()
  CoUninitialize();
}
I would like to improve my function in order to dinamically recognize the type of the variable to write (if "String" or "ByteString"). Any suggestion?

Now I have some problem reading the variables…
Casting the variable to VT_BSTR, VT_SAFEARRAY, VT_CARRAY or VT_ARRAY always fails.
_variant_t vString;
vString.ChangeType(VT_BSTR, &output);
Can you help me?
Thank you!

Best regards,
Federica

Please Log in or Create an account to join the conversation.

More
15 Jun 2019 09:46 #7443 by support
Replied by support on topic Writing ByteString
You need to create a safearray of bytes from your string and pass it to the WriteValue method. The following example writes a "constant" ByteString. You can modify it to write anything you like.

        void WriteValue::ByteString()
	{
		// Initialize the COM library
		CoInitializeEx(NULL, COINIT_MULTITHREADED);
		{
			// Instantiate the client object
			_EasyUAClientPtr ClientPtr(__uuidof(EasyUAClient));
 
			// Prepare the value to be written
			CComSafeArray<BYTE> array(5);
			array.SetAt(0, 11);
			array.SetAt(1, 22);
			array.SetAt(2, 33);
			array.SetAt(3, 44);
			array.SetAt(4, 55);
 
			const CComVariant value(array);
 
			// Perform the operation
			ClientPtr->WriteValue(
				L"http://opcua.demo-this.com:51211/UA/SampleServer", // or "opc.tcp://opcua.demo-this.com:51210/UA/SampleServer"
				L"nsu=http://test.org/UA/Data/;i=10230",
				value);
		}
		// Release all interface pointers BEFORE calling CoUninitialize()
		CoUninitialize();
	}
Best regards
The following user(s) said Thank You: federica

Please Log in or Create an account to join the conversation.

More
13 Jun 2019 12:52 #7440 by federica
Replied by federica on topic Writing ByteString
Yes, I'm passing a string because my value is a CString.

Please Log in or Create an account to join the conversation.

More
13 Jun 2019 12:49 #7439 by support
Replied by support on topic Writing ByteString
Hello,

what type of value are you passing to be written? Are you passing in a string? If so, that would be wrong. It should be an array of bytes.

Best regards

Please Log in or Create an account to join the conversation.

More
13 Jun 2019 10:05 #7438 by federica
Writing ByteString was created by federica
Hi,
I'm using your SDK (QuickOPC 2018.1, in particular OPC-UA under COM with C++) since last year.
We usually write data through WriteValue method.
I'm connected to a Fanuc OPC-UA server and I need to write a ByteString tag.
How can I do this?
I continue to receive casting error: "Cast da 'System.String' a 'System.Byte[]' non valido."

Do you know a way for detecting the type of the tag in order to handle different data type in my source code?

Thank you

Best regards,
Federica

Please Log in or Create an account to join the conversation.

Moderators: support
Time to create page: 0.069 seconds