Make your own free website on Tripod.com





オブジェクトリファレンス



4.オブジェクト一覧

構成図

vba配下にeventとcpuがいるという図(のつもり)です。vba.は省略可(デフォルトオブジェクト)。型はイメージです。typeof(BSTR)=="string", typeof(long)=="number", typeof(void)=="undefined", typeof(DISPATCH)=="object" or "function"
(型の書き方は個人的な好みで書いています。API仕様は予告なく変更する可能性がありますが、そのときはゴメンナサイ←よくある文言じゃの〜)

VBAオブジェクト

プロパティ

output
BSTR output
ダイアログボックスのoutput欄の値を読み書きします。alertボックスを出したくない時などに使用します。
例: output = "テスト";
path
BSTR path
scriptディレクトリへのパス(C:\app\vbalink172lb\scriptというような)を文字列で返却します。設定は出来ません。
例: alert(path);
reset
bool reset
実行ボタンを押した時にリセットするかどうか。通常、スクリプト内で宣言したオブジェクト(変数や関数)の生存期間は、次の実行ボタンが押されるまで生存となっています。が、resetをfalseに設定するスクリプトを実行すると、その次に実行ボタンを押したときに実行されるスクリプトでも生存するようになります(タイマー、イベントも含む)。 
例:
if(typeof(c)==typeof(undefined)){//変数cが存在するか?
  var c=0;  output = c++; //存在しなければ、宣言する。
} else {
  output = c++;
}
reset = false;//この行がない場合はoutput欄は必ず0になるが、あれば実行ボタンを押すたびに1加算される。
noalert
bool noalert
エラー発生時にアラートボックスを出さないようにするかどうか。構文エラー時などはエラー用のアラートボックスを出すようになっていますが、trueに設定すると出さないようにします。これは、new ActiveXObjectなどで他プログラムを起動した際、そのプログラムを閉じてもエラーが出ないようにするというのを想定しています。noalertを設定しても、alertボックスは出すことが出来ます。
例: noalert = true;

メソッド

alert
void alert(BSTR str)
アラートボックスを出します。
例:alert("こんなの使わね〜");
shexec
void shexec(BSTR exe[, BSTR option])
外部プログラムを実行します。ShellExecute関数を呼んでいるだけです。(セキュリティを考えるほどのツールでもないと思ったりしたので)
fileload
void fileload(BSTR path [, bool flg])
pathで示されるファイルをスクリプトファイルとして読み実行する。scriptフォルダからの相対パス。flgがtrueであれば絶対パスとして読みます。ディレクトリは\\という風に\を2つ。共通関数などの読み込みなどをイメージ。
例: fileload("common\\func.js");
fileread
BSTR vba.fileread(BSTR path [, bool flg])
pathで示されるファイルの内容を戻り値として文字列で返却する。scriptフォルダからの相対パス。flgがtrueであれば絶対パスとして読みます。fileloadとの違いは実行せずに読み取るというところだけ(eval()すれば同じになりますが・・・)
例: fileread("ゲーム名\\test.txt");
setTimeout
long setTimeout(BSTR statement [, long miliSec, long ntime])

long setTimeout(function func [, long miliSec, long ntime])
statementをntime回miliSec間隔で実行する。miliSecとntimeは省略可能。miliSec省略時はstatementを1回すぐに実行する(全コードが実行された後)。ntimeが省略された場合は1回実行になります。ntimeがマイナスなら永久に実行し続ける(再度実行ボタンを押すまでの間)。ミリ秒の誤差は30ミリ秒程度あります(SetTimerしているだけ)。
戻り値として"タイマーID"を返却します(複数setTimeoutする場合にどれかを識別するために存在します)。1〜65535までの数値となります。
setTimeoutの呼び出し時にエラーとなった場合は、全てのタイマーがクリアされます。(エラーが出続けるのを防ぐため)
タイマーで呼び出した処理が終了する前に、次のタイマーが呼び出されることはありえません(ただしalertストップは効かない罠)
例:setTimeout("timerProc();" 1000, -1); //1秒に1回timerProcを呼び続ける。
例:setTimeout(timerProc, 1000, -1);//どちらでも指定可能。今のところ引数には何も渡しません。ちなみに第一引数を"timerProc"という風に"でくくる指定でもIEでは可能なようですが、このツールでは出来ません。
clearTimeout
long clearTimeout( [long timerID] )
指定されたタイマーを削除する。timerIDが省略された、もしくは0が指定された場合は全てのタイマーを削除。
例: clearTimeout(tid);
memread1
memread2
memread4
long memread1(ulong addr [, bool sign])
long memread2(ulong addr [, bool sign])
long memread4(ulong addr [, bool sign])
アドレスaddrの値を戻り値として返却。signがtrueなら符号ありとして値を返却します。デフォルトはunsignedです。
読み取り可能なアドレスはどこでも可能(VRAMやROMも可能)
例: var v = memread2( 0x02001000 );
memwrite1
memwrite2
memwrite4
void memwrite1(ulong addr, ulong val)
void memwrite2(ulong addr, ulong val)
void memwrite4(ulong addr, ulong val)
アドレスaddrの値をvalに設定。他はmemread系と同じ。memwrite1に256を渡した場合は、0を設定します(割った余りを入れる)。
書き込み可能なアドレスはどこでも可能(VRAMやROMも可能)
例:  memwrite2( 0x02000000, 0x3f3f);
memread1s
memread2s
memread4s
BSTR memread1s(ulong addr, long num [, bool sign])
BSTR memread2s(ulong addr, long num [, bool sign])
BSTR memread4s(ulong addr, long num [, bool sign])
アドレスaddr開始でXByte*num個分値を読み、10進数値文字列を,(カンマ)区切りで返却。XbyteのXは関数によって違います。memwrite1なら1byteになります。signがtrueなら符号ありとして値を返却します。デフォルトはunsignedです。
例: var unit = memread2s( 0x03000000, 10); //2byte * 10個読み取る(0x03000000 - 0x03000019を読む)
memwrite1s
memwrite2s
memwrite4s
void memwrite1s(ulong addr, BSTR vals)
void memwrite2s(ulong addr, BSTR vals)
void memwrite4s(ulong addr, BSTR vals)
アドレスaddr開始でXByte*valsのカラム数分メモリを書き換える。XbyteのXは関数によって違います。valsは書き換えたい値を10進数値文字列で,(カンマ)区切りで指定。カンマがあるごとに次のByte(4sなら4byte)へ。読み取れない数値は0として扱われ、書き込みが行われます。
例1: memwrite1s( 0x02001000, [ 0x63, 0xFF, 0x63, 0xFF]);
例2: memwrite2s( 0x30000040, "日本語とか, 指定してみる"); // 0x03000040 - 0x03000043が0として設定されます





eventオブジェクト

このツールで最も使えるものです。イベントの有効期間についてもタイマーと同様、再度実行ボタンを押すか、スクリプト実行ダイアログが閉じるまでとなっています。逆に暴走したらダイアログを閉じてください(不可能なことの方が多いですが--;)。さらに注意点として、チート機能と組み合わせた場合の動作について、現在の所、チート機能による固定の上書きが行われるとその数だけ書き込みイベントが発生するようになっています(要は秒間60回呼び出されます)。それぞれ同じアドレスを対象とした時のみですが、ご注意ください。

メソッド

onRead
void onread(ulong addr, function func)
addrで指定されたアドレスが読み出された時に、funcが呼び出されます。SDLで言うならbpr。windowsならhook。
onreadを設定したアドレスに対しmemreadしても関数は呼ばれません。CPUの読み込み命令として読もうとした時(読まれる直前)に呼ばれる。
呼ばれた関数内でそのアドレスの値を書き換えた場合は、即座に有効になる(発行元の命令が書き換えられた値を読むようになる)。
指定可能なアドレスの範囲:
WRAM : 0x02000000 - 0x0203FFFF
IRAM : 0x03000000 - 0x03007FFF
ROM : 0x08000000 - 0x09FFFFFF
これら以外のアドレスに設定使用とした場合は無視されます。
SDL版と同様、アドレスを指定する際は、2byte読みの命令であれば、先頭の方のアドレスを指定しなければならない(後の方のbyteにも設定は出来るがやったところで意味はないです。(2回呼び出されることはない))。
関数に仮引数を指定すれば(もしくはarguments)、いくつかの情報が取得できます。
例:
function f( addr, val){
  output = "設定したアドレス:" + addr.toString(16) + "\r\n現在の値:" + val
  //addr=0x0200100 valはCPUが参照しようとした値
  memwrite2(addr, val+1); //+1した値を書き込む。有効。
  memwrite2(addr+2, 0xFFFF); //これも有効
  cpu.reg(0) = cpu.reg(1); //R0にR1の値を転送。ただしレジスタ操作は不定な動作となるときあり
  memwrite2s(0x06010000, [0,0,0,0,0,0,0,0]); //VRAMなどへの読み書きも有効。
  memwrite2(cpu.pc, 0x573f); //発行元命令の書き換えは有効。ただし現在の命令は実行される
  memwrite2(cpu.pc+2, 0x573f); //発行元命令以外の書き換えも有効。
  event.onread(addr+2, f); //このような指定も可能
  //returnを記述しても意味はない。この後発行元命令は書き換え後の値で命令を実行する。
  alert("stop:"+cpu.pc);//この関数が終了しない限り、次の命令は実行されない
}
event.onread( 0x02001000, f); //0x02001000が読み込まれた時に関数fが呼び出される。
event.onread( 0x02001002, f); //何個も設定することが出来る
レジスタ操作は発行元の命令が使用しないレジスタなら書き換え内容が保証される。使用するレジスタについては不定(ものによる)。フラグレジスタも同様です。
onWrite
void onwrite(ulong addr, function func)

addrで指定されたアドレスが書き込まれたときに、funcが呼び出されます。
使い方はonreadと同じですが、指定可能なアドレスの範囲がreadと比べ、VRAMが追加になっています。
同じアドレスに読みと書きの両方の設定をしても、2つとも有効です。(読みが行われると1回、書き込みが行われると1回呼び出される)。
チート機能と併用は注意お願いします。
onwriteを設定したアドレスに対しmemwriteしても関数は呼ばれません。CPUの書き込み命令として書き込もうとした時(書き込まれる直前)に呼ばれる。
onreadと異なり、呼ばれた関数内でonwriteを設定したアドレスの値を書き換えた場合は、書き換え内容が無視され、CPUが変更しようとした値で書き込まれる(該当アドレス以外については無視されない)。代わりに戻り値を返却すれば、該当アドレスの値を書き換えることが出来る。
onWriteで指定可能なアドレスの範囲:
WRAM : 0x02000000 - 0x0203FFFF
IRAM : 0x03000000 - 0x03007FFF
VRAM : 0x06000000 - 0x0601FFFF
ROM : 0x08000000 - 0x09FFFFFF

関数に仮引数を指定すれば(もしくはarguments)、いくつかの情報が取得できます。

function f( addr, oldval, newval ){
  //addr=0x02001000, oldval=書き換え前の値, newval=書き換え予定の値
  output = "設定したaddr:" + addr.toString(16) + "\r\n変更前:" + oldval + "\r\n変更後:"+ newval;
  memwrite2(addr, newval+1); //これは無効(後で書き換わるため)
  memwrite2(addr+2, newval+1); //これは有効
  cpu.reg(0) = cpu.reg(1); //R0にR1の値を転送。ただしレジスタ操作は不定な動作となるときあり
  memwrite2(cpu.pc, 0x573f); //発行元命令の書き換えは有効。ただし現在の命令は実行される
  memwrite2(cpu.pc+2, 0x573f); //発行元命令以外の書き換えも有効。
  return newval+2;//addrの値を書き込もうとした値に+2した値を書き込む。
  //戻り値を設定しない場合は通常の動作となる(書き込もうとした値(newval)で書き込まれる)
  //この関数が終了しない限り、次の命令は実行されない
}
for(var i=0; i<0xFF; i++){ //何個も設定することが出来る。
  event.onread( 0x02001000+i, f); //0x02001000-0x020010FFに書き込もうとした時に関数fが呼び出される。
}
レジスタ操作は発行元の命令が使用しないレジスタなら書き換え内容が保証される。使用するレジスタについては不定(ものによる)。フラグレジスタも同様です。

onExec
void onexec(ulong addr, function func[, bool armstate])

addrで指定されたアドレスを実行命令として実行しようとしたときに、funcが呼び出されます(実行する直前)。
使い方はonreadと同じですが、ARM用とTHUMB用とで異なります。armstateがtrueならARM用になります。省略時はTHUMB用となります。
ARM/THUMBを取り違えた場合は不定な動作になります。ほとんどの場合THUMBでよい(らしい)です。指定可能なアドレスはどこでも可能となっています。
func内では自アドレスへのオペコード書き換えは無効ですが、それ以外へのアドレスの読み書きは全て有効です。

関数に仮引数を指定すれば(もしくはarguments)、いくつかの情報が取得できます。

function f( addr, opcode){
  //addr=0x08001000, opcode=命令の内容
  output = "設定したアドレス:" + addr.toString(16) + "\r\nオペコード:" + opcode.toString(16);
  memwrite2(addr-0x10, 0x2F4e); //別アドレスへのオペコード書き換えは有効。
  memwrite2(addr, 0x2F4e); //自アドレスへのオペコード書き換えは無効。
  memwrite2(0x02000C32, 0xFFFF); //ワークメモリやVRAMなどへの書き込みは有効。
  cpu.reg(4) = 0xFFFFFFFF; //レジスタ操作は有効。(おそらくプログラムカウンタ以外は)
  //onExecを設置した命令が使用予定のレジスタ・メモリに書き込みを行った場合
  //書き換え後の値で実行される。
  //戻り値を設定しても無視される。
//この関数が終了しない限り、次の命令は実行されない } event.onexec(0x08001000, f);//thumb break event.onexec(0x03002000, f, true);//arm break
onExecを設置したアドレスに対し、メモリ書き換え操作をした場合(onExec呼び出し関数内以外にて)、onExecの設置自体が無効になります。

 

CPUオブジェクト

CPU周りの情報を取得・設定します。

プロパティ

reg
ulong reg(short regno)
レジスタの値を取得・設定します。
R0ならreg(0)で取得できます。 同様に、スタックポインタならreg(13)。プログラムカウンタならreg(15)。リンクレジスタ ならreg(14)となります。
ステータスレジスタはreg(16)でアクセス可能になっています。
例1:output = cpu.reg(15).toString(16); //プログラムカウンタを表示する。
例2:cpu.reg(0)++; //R0を+1する。
PC
SP
LR
N
Z
C
V
I
F
T
ulong PC
ulong SP
ulong LR
bool N
bool Z
bool C
bool V
bool I
bool F
bool T
各レジスタの別名(alias)です。
PC = reg(15)
SP = reg(13)
LR = reg(14)
と同じです。
1文字系はステータスレジスタの各フラグ。
Nフラグであれば、cpu.nとcpu.reg(16)&0x80000000は等価です。
条件フラグはともかくコントロールビット系は参照だけにしておいた方が良いと思われます
例:cpu.z = true; //ゼロフラグをONにする。

メソッド

disArm
disThumb
BSTR disArm(ulong addr[, size] );
BSTR disThumb(ulong addr[, size] );
addrで指定されたアドレスを逆アセンブルする。結果は文字列。
出力フォーマットはメニューのDisassembleと同じです。disArmがARM、disThumbがTHUMBに対応します。
sizeは addr以降のアドレスを何個分出力するかとなっています。
例: output = cpu.disthumb( cpu.pc , 10); //現在実行中の命令を見る

 

 

5.使用例

アドレス0x02000000からハーフワード4つ分の値を0xffff, 0x00ff, 0x00ff, 0xffffに書き換えたい場合。
var s = [0xffff, 0x00ff, 255, 65535];
memwrite2s(0x02000000, s);
↑JavaScriptでは[]でくくると配列で、関数に渡たそうとした時点で引数が文字列なので自動でカンマ区切りにjoinされ、渡されます。
関数内部の文字列解析では0xヘキサ読みに対応していないので上記のようにscript側で変換お願いします。


値を1ずつ増やす
add1(0x02000000);

function add1(addr, p){
 var s = p || 1;
 memwrite1(addr, memread1(addr)+s);
}
メモリの書き換えも数が多くなってくると面倒なのでこういう感じに


1秒に1回、値を1ずつ増やす
var c = 0;
function timerProc(){
 output = c++;
}
setTimeout(timerProc, 1000, -1);
setTimeoutはIEと同じです(回数指定出来るようにはしました)。実行ボタンを押した後でも、変数は生きています。永久指定のタイマーをとめたい場合は、該当行を消して実行を押すか、ダイアログを閉じれば止まります。


あるアドレスのメモリ参照・書き込み回数を見る
var c = [0,0];
event.onread(0x03000000, function readProc(){ c[0]++; output = c; } );
event.onwrite(0x03000000, function writeProc(){ c[1]++; output = c; } );

チート機能のようなことをしてみる
//VBAコードが「02001000:63」の場合
event.onwrite(0x02001000, function(){ return 0x63; }); //0x02001000を99で固定する。

//VBAコードが「02002000:03E7」の場合
event.onwrite(0x02002000, function(){ return 0x3E7; }); //0x02002000を999で固定する。

//条件付書き込み
event.onwrite(0x02003000, function(addr,old,nnew){ if(old!=nnew){ return old; }); //変更されないようにする
やめたい場合は、行を削除してもう一回実行で。
ちなみに、書き換えバイト数(1byteか2byteか)については、内部で記憶しているため、VBAコードのように「XXXX:00」か「XXXX:0000」を分けて記述する必要はない(XXXXの部分にはアドレスが入ります)。

SDL版のようなことをしてみる
event.onread( 0x03000000, f);
//event.onexec(0x08003000, f); //さらにbreakpointを設定したければコピペしてアドレス変える。
function f( addr, val ){
  output = "addr:" + xketa(addr) + "\r\nval:" + xketa(val) + "\r\n";
  for(var i=0; i<16; i++){ output += "R"+i+":"+xketa(cpu.reg(i)) +"  "; if(i%4==3){ output+="\r\n"; } }
  output += (cpu.t)?cpu.disthumb( cpu.pc, 5):cpu.disarm(cpu.pc, 5);
  //alert("stopper"); //読まれるたびに止めたければ、コメントを外す。
}
function xketa(para, keta){//%08x表記
  keta = keta || 8;
  if(para.toString(16).length < keta){ var ret = ""; 
    for(var i=keta; i>para.toString(16).length; i--){ ret += "0" }
    return ret + para.toString(16)
  } else { return para.toString(16) }
}
GUI機能はそのままに解析をおこなえる(かもしれない)。

5. 他プログラム(IEなどを)を使用して値を設定する
アイテムの番号など大抵のデータはindex番号などになっており、さくさく切り替えながらやりたい場合(全アイテムの動作検証をする場合など)は面倒だったりします。そんなときに参考までのソースを示します。
noalert = true; //IEを閉じた時にエラーダイアログが出ないようにする。
fileload("common\\common.js"); //HTMLToDOM
fileload("test\\fe_com.js"); // CreateItemTable
var weapontable = CreateItemTable();
var ie = HTMLToDOM(fileread("test\\test.htm"), true); //ローカルファイルをIEで読む
ie.Navigate("javascript:init(true);"); //初期化関数を呼ぶ(option)
var f = ie.document.form1
function TimerProc(){
	//ieやf経由でIEの値を設定したり取得したりし、memwriteする処理をここに記述する。
}
setTimeout(TimerProc, 1000, -1);
IEを整形表示可能なプロセスメモリエディタとして使用することが出来ます(プニルとかでもいいと思いますが)。ファイル読みなら時間がたってもポインタが有効なのに、URLから起動すると、無効(エラー)となったので注意。I/F作るのが結構大変だったりしますが、やれないことはないです。
6. 40Hごとにキャラの情報が入っている場合に、中の情報に対してXXが高い順にソートする。
var unitnum = 20;
var address = 0x020110000;
var bsize = 0x40;

fileload("common\\func.js");
blocksort(address, bsize, unitnum, 0);

//---func.js---//
function blocksort(addr, blocksize, num, index){//始点アドレス, 1ブロックサイズ, 数, ソートキー
 function cmp(x, y){ return x[index] - y[index]; }
 var ut = [];
 for(var i = 0; i< num; i++){
  ut.push([memread2s(addr + blocksize*i, blocksize/2).split(",")]);
 }
 ut.sort(cmp);
 for(var i = 0; i< num; i++){
  memwrite2s(addr + blocksize*i, ut[i]);
 }
}
だから何だ?という感じですが、呼び出す条件をあるアドレスが実行されたときとか画面のある箇所の色が変わった時とかに実行するように設定すれば、ROMパッチでは難しいような独自の機能を組み込んで遊ぶことが出来ます。(固まるほど思い処理をやらせたい時はDLLを呼び出すようにすればいいと思う。多分・・・)


よく分からない方は コレをDLし、VBAインストールフォルダに解凍してください。
いくつかの使用例を書いています。説明なしです。サンプル悪すぎスマソ。