はにゃ〜〜ん。Workplace shellオブジェクトで困ってる人がいたら, 実体を見せずに忍び寄り こっそり教えちゃう白い影。って, 影が白い訳あるかー, みたいな。
そんなこんなで, 今回, 抽象オブジェクトからアイコンを得るってヤツにょ。
まずは, ソレの使い方から。
/* 抽象オブジェクトからアイコンを得るサンプル。 */ /* 試しに, '<WP_DESKTOP>' にある 'IconVV.exe' を */ /* 探し出して, アイコンをファイルに出力してみる */ options 'ETmode' True = 1; False = 0; call RxFuncAdd 'SysLoadFuncs', 'rexxutil', 'SysLoadFuncs' call SysLoadFuncs ObjID = '<WP_DESKTOP>' hObj = SysIni('User', 'PM_Workplace:Location', ObjID) /* 探したいプログラムを指定する。パス名は付けない。 */ ahEXE = ProgObjPath(hObj, 'IconVV.exe', 'Handle') say 'ハンドル:' c2x(reverse(left(hObj, 2)))'→' ahEXE bin = SysIni('User', 'PM_Abstract:Icons', ahEXE) if bin == 'ERROR:' then do say 'exeファイルの中に含まれてるから, 分かんない。(T-T)' exit end iconFile = '$$temp.ICO' call charout iconFile, bin, 1 call charout iconFile exit内容はコメントにある通りで, Desktopにプログラムがあるとして, その実際のファイル名を指定するってーと, ソレを探し出してハンドルを表示するって処理。
'PM_Abstract:Icons'
を使ってアイコンを取るって訳だもん。
エラー処理にも書かれている通り, *.exeファイルの中に入っているアイコンのばやい, 抽象オブジェクトつってもアイコンを取り出したりはできない。 どーすんのかっつーと, *.exeファイルのヘッダーをアレして取り出すってことになって, ソレはもー大変。 もしかすっと こーゆーのは Toolkitに書かれているかも。探してみてちょ。
それから, ProgObjPath
なんだけど, コレは第三引き数に 'H'とか 'Handle'とか指定すっとハンドルを, そーでなければ 絶対パスを返しちゃう, そーゆーやつ。
探したいファイル名を第二引き数に指定しとくことで, ソレと比較する訳だね。
ProgObjPath: procedure expose driv. node. True False parse arg hObj +2, str, m +1 str = translate(str) Inif = 'User' Key = strip(c2x(reverse(hObj)), 'L', 0) val = SysIni(Inif, 'PM_Abstract:FldrContent', Key) if val == 'ERROR:' then return '' do i = 1 to length(val) by 4 hnd = d2x(c2d(reverse(substr(val, i, 4)))) /* 前ゼロを取るため (strip()でも可) */ obj = SysIni(Inif, 'PM_Abstract:Objects', hnd) p = pos('WPProgramRef', obj) if p > 0 then do parse var obj =(p)'04000b00'x+6 txt +2 if RxWPFileSystem(txt, 'txt') then if translate(FileSpec('N', txt)) == str then if translate(m) \== 'H' then return txt else return hnd end end return ''
処理内容は, 第一引き数で指定したハンドルのフォルダーにある, 抽象オブジェクトのコンテンツを一つ一つ調べて, 同じファイル名があるかどうか調べてるだけ。
その抽象オブジェクトの実体を指すハンドルを, RxWPFileSystemの前の行の parseで取り出してる訳だね。
んで, 処理内容を詳しく解説するってーと ・・
さて, アイコンが exeの中に含まれていて どーしても取り出せないってばやいの対処方法。
ソレは ・・ ソレは ・・・ アイコンをビミョーに編集する。
するとソレが 'PM_Abstract:Icons'になるだよ。ソレで取り出せるって訳。ちょっちインチキっぽいけどね。(^^)
実のところ コレって, アイコンを得る方法は? の回答のつもりなんだけど, でも ホントは, APIを知りたいはずだと思うんで, 全く答えになったいない可能性大。 ま, こーゆー方法もあるってことでアレしてちょ。 それから Warpのページにも解説してたりするにょ。
ふと, アレして 〆(^^) のプログラムを ORexxの環境にして動かしてみた。
白龍のMemoPad編集とか, いくらなんでも動かないだろう・・。
と, 思ったらあっけなく動いた。あれ?, 予想と違う。二重呼び出しとか使いまくってんのに?
そんなに互換性があるのなら認識 改めなきゃ。そー思ったのもつかの間。それ以外の大概のプログラムが動かない (T_T
「拒絶反応・・, くっ, この私を拒絶するというのかっ?」
と, ボケかましていても解決には向かわないんで調べてみることに。
そこで分かったこと。
まだ, 他にもあるかもしんない。でも EAも巨大になるし遅いし, やっぱ Classic一筋がよいかも。 そー思う 〆(^^) であったのこと。
※ 他にもあることを御存じの場合, お知らせ下さい。(まぁ, ここにまとめておきたいだけなんだけど (^^; )
今回は, ソースですかっ? そーっす。(←バカ)
えと, parse 命令 にも source ってーのがあるけど, そーではなくって関数を取り上げる。 動いているそのプログラム自身の sourceを取り出す事ができるとゆーヤツだ。
これはもうインタプリタならではの芸当で, コンパイラにはこれは無理ってものだ。 ORexx とかでも, 中間言語(のよーなもの)に落としてしまっては, これは使えない。 もちろん Rexxコンパイラーでコンパイルしたもの(?)でも, これは使えないだろう。
例えば, 自分自身を栗鼠とするにはー, じゃなくってリスト。
/* source print program */ do i = 1 to sourceline() say sourceline(i) end exitむーん, 何だかばかばかしいプログラム。別にいいんだけど。
いったい, これが何の役に立つのか。それはヒミツだ。ふっふーん, 分かる人には分かるってもんさっ。
ある所ではインストールプログラムに・・って, ゆってんじゃん。
月の始まりなので今回は軽く (←それは関係ないと思うんだけど)。そりでは (^o^)/~~
まるで前回の続きのような, ハンドルのダンプ・プログラム (←"のような"? (^^;)
例えば何か別の言語でアレするとしても, 確認しながら動かすと色々と便利。
でも, だからって『日本語で』とか『英語で』とかゆーのは無理。(←なにゆってんだか(^^;)
/* Workplace handle [dump program] */ options 'ETmode' True = 1; False = 0; call RxFuncAdd 'SysLoadFuncs', 'rexxutil', 'SysLoadFuncs' call SysLoadFuncs ESlist = 'idx' idx = '' call RxWPFileSystemInit say '=== DRIV information ===' do i = 1 to driv.0 v = driv.i say c2x(left(v, 16)) substr(v, 17) /* 前半を16進表示と, 後半はそのまま */ end say '=== NODE information ===' do i = 1 to length(idx) by 2 n = substr(idx, i, 2) v = node.n say c2x(left(v, 28)) '('substr(v, 29)')' /* 前半を16進表示と, 後半はそのまま */ end exit
この後ろにでも, RxWPFileSystemInit:からの処理を付けると, 簡単にソレを表示する事ができるってもんさー。はっは, って忘れ物。この改造がないとダンプできない。
when str == 'NODE' then do parse var val =(p) +4 node +28 -2 ln +1 +1 nodename '0'x n = substr(node, 3, 2)/*;if symbol('node.n') \= 'LIT' then say nodename;*/ idx = idx''n /* ←ココ */ node.n = node''nodename p = p +32 +c2d(ln) +1 end
で, 他の言語でアレするばやい, ここまでは同等のことができるってもんだけど,
関数 RxWPFileSystemを実装ってのはちょいとつらい。
検索するには, nodeの 3Byte目から 2Byteの部分の一覧を作っといて, 一つ一つ調べるとか,
高速化するならハッシュでも用意するとか, 二分検索するとか・・ ちょっち手間かも。
Rexx系の言語では, これを連想配列(っぽいもの?)で扱うと簡単。これは AWKとか, Perl(の機能の上のヤツ) にも同等の機能がある (Perlは使った事ないんだけどね(^^)。
◇
しまった, これ『小物ソフト』ネタに使えたんじゃないのか? (^^)\(バキ☆)
おお, お待たせだったらしい (^-^)
・・で, 前回のが判りにくかったようなので, 『深く静かに説明しよう』モード。
OS2SYS.INI ファイルを INIファイルビュワー(?)で見ると, その中にひときわ大きいものを目にすることができよー。 そー, これこそが WPFileSystemのデータベースなのだー。
アプリケーション名 | キー名 | 値 |
---|---|---|
PM_Workplace:Handles0 | BLOCK1 | Val(28645) |
PM_Workplace:ActiveHandles | HandlesAppName | Val(22)=PM_Workplace:Handles0^@ |
PM_Workplace:Handles1 | BLOCK1 | Val(28602) |
なぜ でっけーのが2つあるかを, 先に説明しよう。
この二つの間に, 文字列を含むのが登録されている。それは片方のデータベースのアプリケーション名になっている。
つまり, そーゆーことなのだ。(←どーゆーことだ)
このデータベースを更新するときは, 新しいデータベースを作成しといて,
指し示している PM_Workplace:ActiveHandlesを切り換える。そーゆー具合にして成長していくわけなのじゃ。
(まるで見てきたようにゆってるけど, 見た訳じゃない。見れるもんでもないけど)
で, なぜ BLOCK1とゆーよーに "1"なのかとゆーと, この例では BLOCK1までだけど, 環境によっては BLOCK2までとか, それ以上とか・・ 3以上は まだお目にかかった事がないけど。 こりは (確認していないけどたぶん)1つのエントリーあたり 64KByteという制限があるためだろー。 データベースを得る方法をまとめると,
◇
あー, 何だか今回も眺め, ちがう 長め。
(↑)の方法で取得したものを, こんどはいろいろアレする訳で・・。
この先頭には, 未確認の 4Byteがついてる。こりゃー無視。
そして, その次に現れるのは "DRIV"か "NODE"の 4文字の文字列。
これ以外を見た事はないんで, (適当だけど)この 2種類しかないんだろうたぶん。きっと。
=== Handle dump V1.0 === AppName=PM_Workplace:Handles1 Block=1 Hed=95BA0000 DRIV EC4C6C000000000015901023D8486C00 [A:] 0100FE940000000000000000000000004C496C00A4A9770101000200 (A:) DRIV E4FF6C00000000001554BDA7AC4C6C00 [D:] 01003BC3000000004C496C0000000000204D6C00644C6C0001000200 (D:) 010068CC3BC3000000000000484B6C0098496C00D8486C0001000C00 (INSTTEMP.EPF) 01006A883BC30000084B6C00D84B6C00904B6C00084B6C0001000800 (OS2IMAGE) 01001C046A880000C04A6C0000000000484B6C00C04A6C0001000200 (FI) 01001E7E1C040000E4496C0000000000084B6C00784A6C0001000800 (BONUSPAK) 01008B371E7E000098496C00784A6C002C4A6C0098496C0001000800 (IBMWORKS) 01002F4E8B3700000000000000000000E4496C004C496C0000000C00 (IBMWDESK.CMD) 0100E13E1E7E00002C4A6C0000000000C04A6C002C4A6C0001000800 (FAXWORKS) 01006318E13E00000000000000000000784A6C00E4496C0000000C00 (FAXWORKS.EXE) 0100EBE03BC30000904B6C00644C6C001C4C6C00904B6C0001000400 (INST) 01002AAFEBE000000000000000000000D84B6C00484B6C0001000800 (J_POCKET) 0100B35B3BC300001C4C6C0000000000AC4C6C001C4C6C0001000800 (J_POCKET) 010069DCB35B00000000000000000000644C6C00D84B6C0000000A00 (README.CMD) |
図(2)の 3 Byte目から 0x3BC3が入っているねっ。これは "D:"を指すハンドルといえよー。
その次の 2 Byteは 0x0000なので, この上には何も存在しないことを意味している。
例えば, 下側の (J_POCKET)は, ハンドル 0xB35B, 上位には 0x3BC3 つまり "D:" ・・とゆーことは root直下っつーことにる。
上側の (J_POCKET)は, ハンドル 0x2AAF, その上位に "INST", その上位に "D:"。
ノード情報の後ろ側。最後の 2 Byteは上で説明したので, その, さらに前の 2Byte。 これはファイルかどうかを意味している。ってとこ。
◇
このデータベースの情報は必ずしも, 実際の物と一致しているわけではない。
Workplaceを介さずに, たとえばコマンドプロンプトで rd xxx とかしても,
このデータベースからは削除されない。いや, もしかしたらこれは増加していく一方なのかもしれない。
これが BLOCK2, 3と, どんどん増えると読み込みも(つまり起動も)時間がかかるし,
稼働中の処理速度も遅くなる。これは必要最小限にすべき情報だと 〆(^^)は思うことがないこともない。
んじゃ, どーすんのさ, これ。
そー, これは・・・
◇
Workplaceより先に 〆(^^)が壊れかけている気がする。・・崩れているのかも。
今回, お待たせ(なのか?)のハンドルからファイル名を ってゆーアレ。
WPFileSystemのヤツ (たぶん(^^;; )。
んー, 今回ちょっと眺め, いや長め。いやー あっはっはー。
インターフェースは WPToolsに合わせてある。
きしょー, こいつめー, にくいねーっ。
使い方は, これ→ Rc = RxWPFileSystem(handle, 'txt')
ハンドルを指定する時は '#'から始まると文字列で, そうでないものから始まると・・。
で, ファイル名は, この場合 txtとゆー変数に入る。コーテーションでくくって文字列で渡すことに注意 (うわ, まじめ)。
フォルダーのばやいは最後に'\'が付いてくる。
関数の戻り値は Rc ... 成功(=True:1)/失敗(=False:0) ってゆー感じ。
RxWPFileSystem: parse arg , RxWPFileSystem; return RxWPFileSystemCore(arg(1)); RxWPFileSystemCore: procedure expose driv. node. True False (RxWPFileSystem) parse arg hObj if length(hObj) > 2 & left(hObj, 1) == '#' then hObj = reverse(x2c(substr(hObj, 2))) if \datatype(driv.0, 'W') then call RxWPFileSystemInit if symbol('node.hObj') == 'LIT' then return False res = '' fDir = c2d(substr(node.hObj, 25, 1)) do while hObj \== '0000'x res = substr(node.hObj, 29)'\'res hObj = substr(node.hObj, 5, 2) end call value RxWPFileSystem, left(res, length(res) -\fDir) return True
なぜ 2つに分かれているのか。それは・・・ あぁ思い出した。 (↓)こっちは iniファイルから読みだす処理専用。
RxWPFileSystemInit: procedure expose driv. node. (ESlist) Inif = 'System' Appl = SysIni(Inif, 'PM_Workplace:ActiveHandles', 'HandlesAppName') if Appl == 'ERROR:' then return val = '' do i = 1 blk = SysIni(Inif, Appl, 'BLOCK'i) if blk == 'ERROR:' then leave val = val''blk end cnt = 0 p = 5 do while p <= length(val) str = substr(val, p, 4) select when str == 'DRIV' then do parse var val =(p) +4 driv +16 drivname '0'x cnt = cnt +1 driv.cnt = driv''drivname p = p +20 +length(drivname) +1 end when str == 'NODE' then do parse var val =(p) +4 node +28 -2 ln +1 +1 nodename '0'x n = substr(node, 3, 2)/*;if symbol('node.n') \= 'LIT' then say nodename;*/ node.n = node''nodename p = p +32 +c2d(ln) +1 end otherwise say 'Error String='s end end driv.0 = cnt return
元々は RxTT16.INFに記述されていたもの。でもどっから入手したかわかんない。うはは。
少し前, RxTT28.INFが Hobbesに上がっているとゆー情報を宇野さんとこから得た。
あれ, だいぶ前だったかな? まあ, いいや。
16とか 28とかはバージョンらしい。RxTT28.INFにも全く同じ内容が記述されていた。
ちょびっと追記。これ, /2マガにも入ってた。(↓)辿りかた。-- 補足 '98.12.18
でもねー, ここの部分の処理って少し変だったんだよねー。 だから改造の手がかなり入っちゃってる。新規に作ったのと変わんないくらい。 だからって, どーってゆーこともないんだけどね (^^;
あうっち。忘れてた。プログラムの先頭にでも True = 1; False = 0;
が,
それと handleを文字列として指定する時は '#hhhh'
ってゆー感じで・・。うじゃ (^o^)/~~
⇒深く静かに解説しよう。