|
Joined: Apr 2010
Posts: 969
Hoopy frood
|
OP
Hoopy frood
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.
|
|
|
|
Joined: Apr 2010
Posts: 969
Hoopy frood
|
OP
Hoopy frood
Joined: Apr 2010
Posts: 969 |
a use-case code example 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
}
}
|
|
|
|
Joined: Dec 2008
Posts: 1,515
Hoopy frood
|
Hoopy frood
Joined: Dec 2008
Posts: 1,515 |
WOW !!! this is crazy good idea, i hope this will be added in next releases...
|
|
|
|
Joined: Dec 2002
Posts: 5,486
Hoopy frood
|
Hoopy frood
Joined: Dec 2002
Posts: 5,486 |
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
Hoopy frood
|
OP
Hoopy frood
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.
|
|
|
|
Joined: Dec 2002
Posts: 5,486
Hoopy frood
|
Hoopy frood
Joined: Dec 2002
Posts: 5,486 |
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
Hoopy frood
|
OP
Hoopy frood
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: ;; 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.
|
|
|
|
Joined: Dec 2002
Posts: 5,486
Hoopy frood
|
Hoopy frood
Joined: Dec 2002
Posts: 5,486 |
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,486
Hoopy frood
|
Hoopy frood
Joined: Dec 2002
Posts: 5,486 |
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
Hoopy frood
|
OP
Hoopy frood
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: 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.
|
|
|
|
Joined: Dec 2002
Posts: 5,486
Hoopy frood
|
Hoopy frood
Joined: Dec 2002
Posts: 5,486 |
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
Hoopy frood
|
OP
Hoopy frood
Joined: Apr 2010
Posts: 969 |
This is very much appreciated
|
|
|
|
Joined: Dec 2002
Posts: 5,486
Hoopy frood
|
Hoopy frood
Joined: Dec 2002
Posts: 5,486 |
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
Hoopy frood
|
OP
Hoopy frood
Joined: Apr 2010
Posts: 969 |
So far, the changes haven't effected my pre-existing scripts, and the additions are working marvelously. Thank you
|
|
|
|
Joined: Jul 2006
Posts: 4,180
Hoopy frood
|
Hoopy frood
Joined: Jul 2006
Posts: 4,180 |
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 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
Hoopy frood
|
OP
Hoopy frood
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.
|
|
|
|
Joined: Jul 2006
Posts: 4,180
Hoopy frood
|
Hoopy frood
Joined: Jul 2006
Posts: 4,180 |
It's not but it's an array, it's the same idea as: 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,180
Hoopy frood
|
Hoopy frood
Joined: Jul 2006
Posts: 4,180 |
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.aspThere 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. 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). 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,180
Hoopy frood
|
Hoopy frood
Joined: Jul 2006
Posts: 4,180 |
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,486
Hoopy frood
|
Hoopy frood
Joined: Dec 2002
Posts: 5,486 |
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
|
|
|
|
|