FileOpen() Test:
I opted to wrap the
FileObject into a class since we would need to implement/overwrite
RawRead/RawWrite to have it return JScript-compatible data for the
VarOrAdrress parameter.
RawRead/RawWrite is not yet implemented in the demo but other
FileObject methods/properties should work.
(your editor must be able to capture stdout for this demo, or you can run it from the console and pipe the output)
Code: Select all
sc := ComObjCreate("ScriptControl")
sc.Language := "JScript"
sc.AddCode("
(
function hello() {
stdout = FileOpen('*', 'w');
stdout.WriteLine('Hello World');
stdout.Close();
}
)")
sc.AddObject("FileOpen", Func("_FileOpen"))
sc.Eval("hello()")
sc := ""
return
_FileOpen(fspec, flags, encoding:="CP0")
{
return new FileObject(fspec, flags, encoding)
}
class FileObject
{
__New(fspec, flags, encoding:="CP0")
{
this.__Ptr := FileOpen(fspec, flags, encoding)
}
__Get(key, args*)
{
if (key ~= "i)^__Handle|AtEOF|Encoding|Length|Pos(ition)?$")
return (this.__Ptr)[key, args*]
}
__Set(key, value, args*)
{
if (key ~= "i)^Encoding|Length|Pos(ition)?$")
return (this.__Ptr)[key] := value
}
__Call(method, args*)
{
if (method ~= "i)^(Read|Write)(Line|U?(Char|Short|Int)|Double|Float|Int64)?|Seek|Tell|Close$")
return (this.__Ptr)[method](args*)
}
RawRead(ByRef VarOrAddress, bytes)
{
; need to wrap VarOrAddress to JScript-compatible object
}
RawWrite(ByRef VarOrAddress, bytes)
{
; need to wrap VarOrAddress to JScript-compatible object
}
}
VarSetCapacity() proof of concept:
Code: Select all
sc := ComObjCreate("ScriptControl")
sc.Language := "JScript"
sc.AddCode("
(
function test() {
var shell = new ActiveXObject('WScript.Shell');
var RECT = VarSetCapacity(16, 0);
shell.Popup('RECT size: ' + RECT.Size);
// put data
for (var i = 0; i < 4; i++) {
RECT.PutInt(i + 1);
}
// read data
var offset;
for (var i = 0; i < 4; i++) {
offset = i * 4
shell.Popup('Offset ' + offset + ': ' + RECT.GetInt(offset));
}
// write and read string
var buf = VarSetCapacity(256); // ensure size
buf.WriteUTF8('Hello World');
buf.Seek(0); // reset pointer
shell.Popup(buf.ReadUTF8());
}
)")
sc.AddObject("VarSetCapacity", Func("_VarSetCapacity"))
sc.Eval("test()")
sc := ""
return
_VarSetCapacity(size, fillbyte:=0)
{
return new AhkBuffer(size, fillbyte)
}
/* Buffer class
*
* NumPut|NumGet routines
* Methods:
* PutNumType(num [, offset])
* GetNumType([, offset])
* - NumType can be any of the AHK num types. If offset is
* omitted, the internal pointer is used.
*
* StrPut|StrGet routines
* Methods:
* Read([length, enc])
* Write(str [, length, enc])
* ReadEnc([length])
* WriteEnc(str [, length])
* - where 'Enc' can be 'UTF(8|16)' OR 'CPn'. 'CP0' if omitted
*
* Others:
* Seek(distance [, origin := 0]) - Similar to FileObject.Seek()
* Size - returns the size of the buffer
*/
class AhkBuffer ;// temporary name, rename to something cooler
{
__New(size, fillbyte:=0)
{
ObjSetCapacity(this, "_", Abs(size))
addr := ObjGetAddress(this, "_")
DllCall("RtlFillMemory", "Ptr", addr, "UPtr", size, "UChar", fillbyte)
this.Pos := this.__Ptr := addr
}
__Call(method, args*)
{
static ObjPush := Func(A_AhkVersion < "2" ? "ObjInsert" : "ObjPush")
if (method = "Put" || method = "Get")
method .= "UPtr"
if (method = "Read" || method = "Write")
method .= "CP0"
if (method ~= "i)^((Put|Get)|(Read|Write))[A-W0-9]+$")
{
n := 0
if RW := InStr("RW", SubStr(method, 1, 1))
n := InStr(method, "r")
%ObjPush%(args, SubStr(method, 4 + n))
return this[RW ? "_Str" : "_Num"](SubStr(method, 1, 3 + n), args*)
}
}
_Num(action, num:="UPtr", at:="UPtr", type:="UPtr")
{
if (action = "Get") ; adjust the arguments
type := at, at := num
if (at ~= "i)^U?(Char|Short|Int|Ptr)|Double|Float|Int64$")
type := at, at := this.Pos
ptr := this.__Ptr
if !(at >= ptr && at < ptr + this.Size)
at := ptr + at
if (action = "Put")
return this.Pos := NumPut(num, at + 0, type)
static sizeof := { "Char": 1, "Short": 2, "Int": 4, "Float": 4
, "Double": 8, "Int64": 8, "Ptr": A_PtrSize }
this.Pos += sizeof[LTrim(type, "Uu")]
return NumGet(at + 0, type)
}
_Str(action, args*)
{
enc := "CP0"
for i, arg in args
{
if (arg ~= "i)^UTF-?(8|16)|CP\d+$")
{
if InStr(enc := arg, "UTF")
args[i] := enc := "UTF-" . LTrim(SubStr(enc, 4), "-")
break
}
}
static ObjRemoveAt := Func(A_AhkVersion < "2" ? "ObjRemove" : "ObjRemoveAt")
addr := this.Pos
str := (read := (action = "read")) ? StrGet(addr, args*) : %ObjRemoveAt%(args, 1)
BytesPerChar := (enc = "UTF-16" || enc = "CP1600") ? 2 : 1
this.Pos += (StrPut(str, enc) * BytesPerChar)
return read ? str : StrPut(str, addr, args*)
}
Size {
get {
return ObjGetCapacity(this, "_")
}
}
Seek(distance, origin:=0)
{
if (distance < 0 && origin != 2)
origin := 2
start := origin == 0 ? this.__Ptr
: origin == 1 ? this.Pos
: origin == 2 ? this.__Ptr + this.Size
: 0
return start ? this.Pos := start + distance : 0
}
}