mIRC Home    About    Download    Register    News    Help

Print Thread
Page 1 of 2 1 2
Joined: Apr 2010
Posts: 969
F
Hoopy frood
OP Offline
Hoopy frood
F
Joined: Apr 2010
Posts: 969
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
Joined: Apr 2010
Posts: 969
F
Hoopy frood
OP Offline
Hoopy frood
F
Joined: Apr 2010
Posts: 969
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
Joined: Dec 2008
Posts: 1,515
Hoopy frood
Offline
Hoopy frood
Joined: Dec 2008
Posts: 1,515
WOW !!! this is crazy good idea, i hope this will be added in next releases...


Need Online mIRC help or an mIRC Scripting Freelancer? -> https://irc.chathub.org <-
Joined: Dec 2002
Posts: 5,408
Hoopy frood
Offline
Hoopy frood
Joined: Dec 2002
Posts: 5,408
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?

Joined: Apr 2010
Posts: 969
F
Hoopy frood
OP Offline
Hoopy frood
F
Joined: Apr 2010
Posts: 969
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
Joined: Dec 2002
Posts: 5,408
Hoopy frood
Offline
Hoopy frood
Joined: Dec 2002
Posts: 5,408
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.

Joined: Apr 2010
Posts: 969
F
Hoopy frood
OP Offline
Hoopy frood
F
Joined: Apr 2010
Posts: 969
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
Joined: Dec 2002
Posts: 5,408
Hoopy frood
Offline
Hoopy frood
Joined: Dec 2002
Posts: 5,408
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.

Joined: Dec 2002
Posts: 5,408
Hoopy frood
Offline
Hoopy frood
Joined: Dec 2002
Posts: 5,408
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.

Joined: Apr 2010
Posts: 969
F
Hoopy frood
OP Offline
Hoopy frood
F
Joined: Apr 2010
Posts: 969
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
Joined: Dec 2002
Posts: 5,408
Hoopy frood
Offline
Hoopy frood
Joined: Dec 2002
Posts: 5,408
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.

Joined: Apr 2010
Posts: 969
F
Hoopy frood
OP Offline
Hoopy frood
F
Joined: Apr 2010
Posts: 969
This is very much appreciated


I am SReject
My Stuff
Joined: Dec 2002
Posts: 5,408
Hoopy frood
Offline
Hoopy frood
Joined: Dec 2002
Posts: 5,408
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.

Joined: Apr 2010
Posts: 969
F
Hoopy frood
OP Offline
Hoopy frood
F
Joined: Apr 2010
Posts: 969
So far, the changes haven't effected my pre-existing scripts, and the additions are working marvelously. Thank you


I am SReject
My Stuff
Joined: Jul 2006
Posts: 4,141
W
Hoopy frood
Offline
Hoopy frood
W
Joined: Jul 2006
Posts: 4,141
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
}


#mircscripting @ irc.swiftirc.net == the best mIRC help channel
Joined: Apr 2010
Posts: 969
F
Hoopy frood
OP Offline
Hoopy frood
F
Joined: Apr 2010
Posts: 969
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
Joined: Jul 2006
Posts: 4,141
W
Hoopy frood
Offline
Hoopy frood
W
Joined: Jul 2006
Posts: 4,141
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!


#mircscripting @ irc.swiftirc.net == the best mIRC help channel
Joined: Jul 2006
Posts: 4,141
W
Hoopy frood
Offline
Hoopy frood
W
Joined: Jul 2006
Posts: 4,141
Thanks you for improving $comval() for more array support.

I have found some issue with the RegRead method : https://www.vbsedit.com/html/1b567504-59f4-40a9-b586-0be49ab3a015.asp

There are some path which I can see in regedit.exe which report an error for the RegRead $com call function, but it works otherwise, no idea why.

Code
The RegRead method returns values of the following five types.

Type		Description						In the Form of

REG_SZ		A string						A string

REG_DWORD	A number						An integer

REG_BINARY	A binary value						A VBArray of integers

REG_EXPAND_SZ	An expandable string (e.g., "%windir%\\calc.exe")	A string

REG_MULTI_SZ	An array of strings					A VBArray of strings




Whenever the path is ok, REG_SZ and REG_DWORD type are returning correct value (I would think REG_EXPAND_SZ also works, did not try).

Code
alias regread {
  .comopen a WScript.Shell
  var %err OK,%b
  if ($comerr) var %err COM_ERR
  elseif (!$com(a,RegRead,3,bstr,$1)) || ($comerr) var %err COM_ERR
  else %b = $com(a).result
  :error
  if ($error) reseterror
  if ($com(a)) .comclose a
  return %err %b
}


What works:
$regread(HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\FileSystem\NtfsDisable8dot3NameCreation) return 0 if short finename is enabled, 1 if it's disabled (REG_DWORD)
$regread(HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProductName) returns the name of the operating system (REG_SZ - use abbreviated HKLM root item)
$regread(HKEY_LOCAL_MACHINE\SOFTWARE\Intel\PSIS\PSIS_DECODER\GraphFile) (REG_SZ)


What doesn't work:
$regread(HKEY_LOCAL_MACHINE\SOFTWARE\videoLAN\VLC\Language) (REG_SZ)

In the regedit editor, the key is literaly like this, with lower case for 'video', but note that the path alone can be tested, for invalid path you get a com error, for valid path, no com error:

$regread(HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\) is OK while $regread(HKEY_LOCAL_MACHINE\SOFTWARE\videoLAN\) is COM_ERR,

And here is another failing example $regread(HKEY_LOCAL_MACHINE\SOFTWARE\Realtek\Network\install)
but this time $regread(HKEY_LOCAL_MACHINE\SOFTWARE\Realtek\) is OK while $regread(HKEY_LOCAL_MACHINE\SOFTWARE\Realtek\Network\) isn't, it's pretty weird to me.


In any case, I'd like to get support for REG_BINARY and REG_MULTI_SZ when we use $com(name,&binvar).result, I tried REG_BINARY but $com seems to return 0. Are they supposed to work? I believe not.


#mircscripting @ irc.swiftirc.net == the best mIRC help channel
Joined: Jul 2006
Posts: 4,141
W
Hoopy frood
Offline
Hoopy frood
W
Joined: Jul 2006
Posts: 4,141
About my previous post and the fail, I tried on someone's win10 machine, and there was no problem reading string/integer, so it may be an issue with my machine only, no idea why though.

The suggestion for REG_BINARY and REG_MULTI_SZ still stand though.


#mircscripting @ irc.swiftirc.net == the best mIRC help channel
Joined: Dec 2002
Posts: 5,408
Hoopy frood
Offline
Hoopy frood
Joined: Dec 2002
Posts: 5,408
Quote
The suggestion for REG_BINARY and REG_MULTI_SZ still stand though.

You can read these by saving them to a binary variable, eg. $com(name, &value).result

Page 1 of 2 1 2

Link Copied to Clipboard