mIRC Home    About    Download    Register    News    Help

Print Thread
VT_ARRAY when retrieving COM results #259631 05/01/17 03:38 PM
Joined: Apr 2010
Posts: 938
F
FroggieDaFrog Offline OP
Hoopy frood
OP Offline
Hoopy frood
F
Joined: Apr 2010
Posts: 938
As far as I can tell, mIRC does not support VT_ARRAY(binary byte arrays) when it comes to retrieving data from a COM. It'd be great to see this added, especially with the inclusion of com bvar support.

When $com().result is called, if
...the output ISN'T a bvar, convert to string
...the output IS a bvar, fill the bvar with the binary data

The use case:
Using an MS/Windows provided HTTP request object, namely SERVERXMLHttpRequest to retrieve data from a website, the body can be retrieved using .responseBody as a byte array but mIRC is unable to handle such a result, resulting in the returned value being null

Last edited by FroggieDaFrog; 05/01/17 03:44 PM.

I am SReject
My Stuff
Re: VT_ARRAY when retrieving COM results [Re: FroggieDaFrog] #259659 07/01/17 05:24 AM
Joined: Apr 2010
Posts: 938
F
FroggieDaFrog Offline OP
Hoopy frood
OP Offline
Hoopy frood
F
Joined: Apr 2010
Posts: 938
a use-case code example
Code:
alias example {
  var %Error


  ;; Create an instance of MS provided http requester
  ;; and use it to request http://example.com
  .comopen example MSXML2.SERVERXMLHttp.6.0
  if (!$com(example) || $comerr) {
    %Error = Unable to create an instance of MSXML2.SERVERXMLHttp.6.0
  }
  elseif (!$com(example, open, 1, bstr, GET, bstr, http://example.com, bool, false) || $comerr) {
    %Error = Unable to initialize the request
  }
  elseif (!$com(example, send, 1) || $comerr) {
    %Error = Request failed
  }
  else {



    ;; To get the response as purely text, this works flawlessly
    if (!$com(example, responseText, 2) || $comerr) {
      %Error = Failed to retrieve response text
    }
    else {
      noop $com(example, &example).result
      echo -s Reponse Text( $+ $bvar(&example, 0) $+ ): $bvar(&example, 1, 4000).text
      echo -s -
      bunset &example
    }


    ;; But to retrieve the response body as binary data
    ;; This echos an empty string due to mIRC being unable
    ;; to handle VT_ARRAYs
    if (!$com(example, responseBody, 2) || $comerr) {
      %Error = Failed to retrieve response text
    }
    else {
      noop $com(example, &example).result
      echo -s Reponse Body( $+ $bvar(&example, 0) $+ ): $bvar(&example, 1, 4000).text
      echo -s -
      bunset &example
    }

  }


  ;; Handle errors
  :Error
  if ($error) {
    %Error = $v1
    reseterror
  }
  if ($com(example)) {
    .comclose example
  }
  if (%Error) {
    echo -s Error: $v1
  }
}


I am SReject
My Stuff
Re: VT_ARRAY when retrieving COM results [Re: FroggieDaFrog] #259662 07/01/17 02:00 PM
Joined: Dec 2008
Posts: 1,511
westor Offline
Hoopy frood
Offline
Hoopy frood
Joined: Dec 2008
Posts: 1,511
WOW !!! this is crazy good idea, i hope this will be added in next releases...

Re: VT_ARRAY when retrieving COM results [Re: FroggieDaFrog] #259687 12/01/17 09:03 AM
Joined: Dec 2002
Posts: 4,653
Khaled Offline
Hoopy frood
Offline
Hoopy frood
Joined: Dec 2002
Posts: 4,653
mIRC currently handles twenty variant types. In the case of the example you provided, the variant type is VT_UI1, which is a single byte, so it would be easy enough to copy it into a binary variable. For multibyte types, the binary variable would need to be filled with multibyte values and the scripter would have to know the byte size of the type in order to parse the binary variable. In the case of VT_BSTR, the binary variable would need to be filled with multiple, consecutive strings (that are first converted from BSTR to UTF-8), each terminated with a NULL character, and the scripter would need to parse the binary variable accordingly.

The byte sizes for the variant types are:
1: VT_I1, VT_UI1
2: VT_I2, VT_UI2, VT_BOOL
4: VT_I4, VT_UI4, VT_R4, VT_INT, VT_UINT, VT_ERROR
8: VT_I8, VT_UI8, VT_R8, VT_CY, VT_DATE, VT_DECIMAL
?: VT_BSTR, VT_DISPATCH, VT_UNKNOWN

So far, I have tested VT_UI1 with the example you provided. Do you have examples that return arrays of other variant types? And one that returns an array of VT_BSTR?

Re: VT_ARRAY when retrieving COM results [Re: Khaled] #259690 12/01/17 12:52 PM
Joined: Apr 2010
Posts: 938
F
FroggieDaFrog Offline OP
Hoopy frood
OP Offline
Hoopy frood
F
Joined: Apr 2010
Posts: 938
My main concern was for VT_UI1 typed VT_ARRAYs as many MS-provided objects return strings in this type(why not just a BSTR; only MS knows).

I do not have examples of VB_BSTR or other types in use and my search has come up empty, if I do stumble up on such I'll be sure to let you know.

Last edited by FroggieDaFrog; 12/01/17 12:52 PM.

I am SReject
My Stuff
Re: VT_ARRAY when retrieving COM results [Re: FroggieDaFrog] #259692 12/01/17 04:15 PM
Joined: Dec 2002
Posts: 4,653
Khaled Offline
Hoopy frood
Offline
Hoopy frood
Joined: Dec 2002
Posts: 4,653
No problem, I found a way to create arrays of different variant types to test the array parsing code and it seems to handle arrays of VT_BSTR and other types fine. This should be in the next beta.

Re: VT_ARRAY when retrieving COM results [Re: Khaled] #259703 13/01/17 02:26 PM
Joined: Apr 2010
Posts: 938
F
FroggieDaFrog Offline OP
Hoopy frood
OP Offline
Hoopy frood
F
Joined: Apr 2010
Posts: 938
To add to this feature request is there a chance you would add some way for us to pass data into a COM instance as a VT_ARRAY containing VT_UI1 items? Again, this is how many MS-provided objects represent raw byte data(such as the contents of a non-text file).


Something along the lines of:
Code:
;; Where <TYPE> is the contained items' type
$com(name, member, method, array [&]type[* varname], &bvar|inputString)

ex:
$com(name, member, method, array &ui1, &bvar)

Personally I'd only consider fixed-length array-item types for this and have checks to make sure the amount of bytes in the input is divisible by the fixed-length of the item-type prior to making the COM call.

Last edited by FroggieDaFrog; 13/01/17 03:16 PM.

I am SReject
My Stuff
Re: VT_ARRAY when retrieving COM results [Re: FroggieDaFrog] #259706 13/01/17 07:53 PM
Joined: Dec 2002
Posts: 4,653
Khaled Offline
Hoopy frood
Offline
Hoopy frood
Joined: Dec 2002
Posts: 4,653
Okay, it looks like I will need to leave this, and the original request, for the next version as they both require critical changes to the COM routines. On to-do list however.

Re: VT_ARRAY when retrieving COM results [Re: FroggieDaFrog] #259743 20/01/17 11:56 AM
Joined: Dec 2002
Posts: 4,653
Khaled Offline
Hoopy frood
Offline
Hoopy frood
Joined: Dec 2002
Posts: 4,653
Can you provide an example $com() call that passes an array of ui1 into a COM instance? Ideally, a method that I can use to verify that the array is being passed correctly.

Re: VT_ARRAY when retrieving COM results [Re: Khaled] #259744 20/01/17 02:27 PM
Joined: Apr 2010
Posts: 938
F
FroggieDaFrog Offline OP
Hoopy frood
OP Offline
Hoopy frood
F
Joined: Apr 2010
Posts: 938
If I read correctly you are looking for an example of passing a UI1 array INTO a com instance, correct? If so the below example will write the specified data to file for you to verify:

Code:
alias ui1_inputTest {

  ;; DATA TO PASS INTO THE THE COM AS A UI1 ARRAY  
  bset -t &ui1_data 1 this is some data to send as ui1_array
  
  
  comopen ui1_test ADODB.Stream
  if (!$com(ui1_test) || $comerr) {
    echo -a failed to create stream instance
  }
  elseif (!$com(ui1_test, open, 1) || $comerr) {
    echo -a Failed to open stream
  }
  elseif (!$com(ui1_test, type, 4, integer, 1) || $comerr) {
    echo -a Failed to set the read/write type to binary
  }

  
  ;; THIS LINE PASSES A UI1 ARRAY INTO THE COM
  elseif (!$com(ui1_test, write, 1, array &ui1, &ui1_data) || $comerr) {
    echo -a Failed to write data to stream
  }
  
  
  elseif (!$com(ui1_test, position, 4, integer, 0) || $comerr) {
    echo -a Failed to reset position
  }
  elseif (!$com(ui1_test, saveToFile, 1, bstr, $mircdirui1_text.dat, integer, 2) || $comerr) {
    echo -a Failed to save to file
  }
  elseif (!$com(ui1_test, close, 1) || $comerr) {
    echo -a Failed to close stream
  }
  else {
    echo -a All done; check $mircdirui1_text.dat to see what was wrote
  }
  
  if ($com(ui1_test)) .comclose ui1_test
}

Last edited by Khaled; 20/01/17 06:59 PM.

I am SReject
My Stuff
Re: VT_ARRAY when retrieving COM results [Re: FroggieDaFrog] #259746 20/01/17 07:13 PM
Joined: Dec 2002
Posts: 4,653
Khaled Offline
Hoopy frood
Offline
Hoopy frood
Joined: Dec 2002
Posts: 4,653
Thanks, both of your examples appear to be working with the new array support, so it is looking good. For the time being, I have limited array support to one dimensional VT_UI1/VT_I1 arrays. This should be in the next beta.

Re: VT_ARRAY when retrieving COM results [Re: Khaled] #259752 22/01/17 07:47 PM
Joined: Apr 2010
Posts: 938
F
FroggieDaFrog Offline OP
Hoopy frood
OP Offline
Hoopy frood
F
Joined: Apr 2010
Posts: 938
This is very much appreciated


I am SReject
My Stuff
Re: VT_ARRAY when retrieving COM results [Re: FroggieDaFrog] #259784 26/01/17 12:44 PM
Joined: Dec 2002
Posts: 4,653
Khaled Offline
Hoopy frood
Offline
Hoopy frood
Joined: Dec 2002
Posts: 4,653
I have uploaded a beta with these changes. It required changes to the way $com() results are handled, so $com() will need some general testing, in addition to testing the above changes, to make sure that it is working correctly.

Re: VT_ARRAY when retrieving COM results [Re: Khaled] #259789 26/01/17 08:40 PM
Joined: Apr 2010
Posts: 938
F
FroggieDaFrog Offline OP
Hoopy frood
OP Offline
Hoopy frood
F
Joined: Apr 2010
Posts: 938
So far, the changes haven't effected my pre-existing scripts, and the additions are working marvelously. Thank you


I am SReject
My Stuff
Re: VT_ARRAY when retrieving COM results [Re: Khaled] #263802 27/09/18 10:47 PM
Joined: Jul 2006
Posts: 3,620
W
Wims Offline
Hoopy frood
Offline
Hoopy frood
W
Joined: Jul 2006
Posts: 3,620
Hey,

I'm not sure but it looks like I might need this for $comval, the Win32_NetworkAdapterConfiguration class and its IPAddress property returns an array of string but mIRC returns $null.

If this is right, something like $comval(name,N,member,[&output]) could be made


Code:
alias localip {
  .comopen a wbemScripting.swbemLocator | .comclose a $com(a,connectserver,3,bstr,.,bstr,root\cimv2,dispatch* b)
  .comclose b $com(b,execquery,3,bstr,SELECT * FROM Win32_NetworkAdapterConfiguration WHERE IPEnabled = True ,dispatch* c)
  var %b $comval(c,0),%r
  while (%b) {
   ; if ($comval(c,%b,DHCPEnabled)) %r = %r $comval(c,%b,DHCPServer)
   ; else
   %r = %r $comval(c,%b,IPAddress)
    dec %b
  }
  .comclose c
  return %r
}


Looking for a good help channel about mIRC? Check #mircscripting @ irc.swiftirc.net
Re: VT_ARRAY when retrieving COM results [Re: Wims] #263819 28/09/18 10:44 PM
Joined: Apr 2010
Posts: 938
F
FroggieDaFrog Offline OP
Hoopy frood
OP Offline
Hoopy frood
F
Joined: Apr 2010
Posts: 938
That isn't a VT_ARRAY; that is an enumerable collection

But it does bring to point two things:

1: There's no way AFAIK to access enumerable collection items with $com() and no way to dispatch collection items with $comval

2: There's no way to access enumerable collection items that are what would be considered primitives(booleans, numbers, strings)

Last edited by FroggieDaFrog; 28/09/18 10:52 PM.

I am SReject
My Stuff
Re: VT_ARRAY when retrieving COM results [Re: FroggieDaFrog] #263820 28/09/18 11:05 PM
Joined: Jul 2006
Posts: 3,620
W
Wims Offline
Hoopy frood
Offline
Hoopy frood
W
Joined: Jul 2006
Posts: 3,620
It's not but it's an array, it's the same idea as:
Quote:
In the case of VT_BSTR, the binary variable would need to be filled with multiple, consecutive strings (that are first converted from BSTR to UTF-8), each terminated with a NULL character, and the scripter would need to parse the binary variable accordingly.
described above, we could get the array inside a binvar and deal with NULL.

There's no need for $com to handle collections as $comval was made to do it, just need array support!


Looking for a good help channel about mIRC? Check #mircscripting @ irc.swiftirc.net