HSPポータル
サイトマップ お問い合わせ


HSPTV!掲示板


未解決 解決 停止 削除要請

2015
1208
NoapHSPコールバックモジュール10解決


Noap

リンク

2015/12/8(Tue) 05:51:30|NO.73509

HSPコールバックモジュールが完成して役にたちそうなサンプルができました

このモジュールで今までコールバック関数が求められたときはCなどで書かなければいけなっかたのが
HSPでできます
サブルーチンをcallfuncで呼び出せます

HSPコールバックモジュールのページ ほかの別のスレッドに投稿していたサンプルもあります
http://nopswebpages.webcrow.jp/apps/ccallfn/

モジュール本体 移動するかもしれません
http://nopswebpages.webcrow.jp/apps/ccallfn/ccallfn.txt

サンプル

#uselib "dbghelp.dll" #func EnumerateLoadedModules "EnumerateLoadedModules" sptr,sptr,int #uselib "kernel32.dll" #cfunc GetCurrentProcess "GetCurrentProcess" dim int_length_list_modules,1 dim int_number_get,1 dim p_fn_EnumLoadedModulesProc,1 makeclbkfunc p_fn_EnumLoadedModulesProc, 4, *label_fn_EnumLoadedModulesProc //リスト取得に必要なバッファサイズ取得 int_number_get=-1 EnumerateLoadedModules GetCurrentProcess(), p_fn_EnumLoadedModulesProc //リスト取得 sdim str_list_modules, int_length_list_modules int_number_get=0 EnumerateLoadedModules GetCurrentProcess(), p_fn_EnumLoadedModulesProc //int_length_list_modules-=2 //改行分 mes "読みこんでいるDLLなど"//\nリストの大きさ="+int_length_list_modules+"バイト" mesbox str_list_modules,ginfo_winx,ginfo_winy-ginfo_cy,4 stop *label_fn_EnumLoadedModulesProc argclbkfunc arr_int_funcargs dupptr str_clone_module_name, arr_int_funcargs.0, 1, vartype("str") if int_number_get>=0{ if int_number_get: str_list_modules+= "\n" str_list_modules += str_clone_module_name int_number_get++ }else{ int_length_list_modules += (strlen(str_clone_module_name)+2) } return 1



この記事に返信する


tds12

リンク

2015/12/8(Tue) 14:28:31|NO.73511

さすがに、2人目になると洗練されて、美しいですね。
http://hsp.tv/play/pforum.php?mode=all&num=62130

どうにしたらこれほどコンパクトにできるのかわかりません。
しかも、nop命令で整形されていて、読みやすいですね。
ライセンスもゆるくて、使いやすそうです。

thiscallのWin32版は、ecxにthisポインタが入るようです。
それと、引数の書き換え防止もあると、よりよくなると思います。



Noap

リンク

2015/12/8(Tue) 18:29:49|NO.73514

tds12さんがすでにつくられていたということにとてもおどろきました

コンパクトなのは主にコンパイラの最適化のおかげかと思います。
もとのコードは見ればわかる通りとにかく分かりやすさ優先でした。
スタックをコピーしたバッファをlparamに渡しておりさらにargclbkfuncでそれをコピーした変数を扱うようにしているので、引き数の書き換え防止になっていると思います。
thisポインタはわたしの環境では引数の第一引数の前にあるようになっています。今見てみるとねぼけていたのかなぜか引き数の最後にあると説明してあって取り出せないようになっているので直します。
古い本の付録を使っているのでtds12さんの使っているコンパイラとは多分ちがうようです。

thisポインタの確認に使ったテストコード

class my_class{ private: int my_privite_integer; public : int my_function1(int, int); int my_function2(int, ...); }; int my_class:: my_function1(int my_function_argument1, int my_function_argument2){ (*this).my_privite_integer = my_function_argument1; return my_function_argument2; } int my_class:: my_function2(int my_function_argument1, ...){ (*this).my_privite_integer = *(&my_function_argument1 + 1); return my_function_argument1; }



tds12

リンク

2015/12/8(Tue) 20:15:33|NO.73518

>tds12さんがすでにつくられていたということにとてもおどろきました
私のモジュールの影響なくこのようなモジュールになるとは、驚きました。
工夫を重ねていけば、ほぼ同じ答えが出るということでしょう。

>modclbkより、
>#define global newclbk3(%1,%2 = 0,%3,%4 = 0)
>//新しい関数ポインタを取得する
>// %1...関数ポインタを受け取る変数
>// %2...引数の数
>// %3...呼び出されるラベル
>// %4...作成のモード(CLBKMODE)
>#define global CLBKMODE_CDECL $00000001
>// 呼び出し規約をcdeclに設定する

>noapさんのモジュールより
>//コールバック関数の作成
>//makeclbkfunc p1,p2,3,p4
>//p1=変数名 コールバック関数が必要な関数に渡すためのポインタ(サブルーチンを呼ぶコールバック関数へのポインタ)が入る変数
>//p2=0~(0) 渡される引き数の数 (callfuncの引数の数え方と同じです)
>//p3=ラベル名 コールバック関数として呼ばれるサブルーチンのラベル


>modclbkより
>#define global clbkargprotect(%1) lp@modclbk3a1=lparam:wp@modclbk3a1=wparam:dupptr args@modclbk3a1,lp@modclbk3a1,wp@modclbk3a1*4,4:dim %1,wp@modclbk3a1:memcpy %1,args@modclbk3a1,wp@modclbk3a1*4
>//引数を取得する
>// %1...引数を受け取るための変数
>//p4=0|1(0) 呼び出し規約の設定 0=stdcall 1=cdecl p4を省略するとstdcallになります

>//引き数の取得
>//argclbkfunc p1
>//p1=変数名 引き数を取得する変数

>modclbkより
>dupptr winh,lparam,wparam*4,4
>//lparam には引数の配列へのメモリアドレスが、
>//wparam には配列の要素数が格納されているので
>//このようにして引数を受け取る

>noapさんのモジュールより
>dupptr x,lparam,wparam*4

なんと、引数はいじらず、命令名だけ変えれば、同じことができました。
素晴らしい完全互換性です。

#uselib "user32.dll" #func EnumWindows "EnumWindows" int,int #func GetWindowText "GetWindowTextA" int,int,int title "コールバックモジュール" dim clbkptr,1 dim i,1 sdim tmpwns,64 sdim wns makeclbkfunc clbkptr,2,*ew makeclbkfunc clbkptr2,2,*ew2 //ここでは、 //clbkptrにewlbを呼ぶ、 //引数が2つのコールバック関数を2つ作っている EnumWindows clbkptr,0 i = 0 EnumWindows clbkptr2,0 title "トップレベルウィンドウ数:"+i mesbox wns,640,480,4,0 stop *ew argclbkfunc winh//二度目以降は知らない GetWindowText winh.0,varptr(tmpwns),64 wns = wns + str(winh(0)) + "\t" + tmpwns + "\n" return 1 *ew2 i++ return 1
//http://hsp.tv/play/pforum.php?mode=all&num=62130のNO.66878、サンプルより改変



Noap

リンク

2015/12/8(Tue) 23:42:46|NO.73523

thisポインタについての説明を修正しました。
もともとcallfuncの仕組みを知ろうとしてどう関数は呼び出されるのかを勉強?していて、その実験として作成しました。
使い勝手のできるだけいいモジュールをつくろうと思ってこうなりました。
違う点としてはtds12さんのはstatにポインタが入るようになっていてわたしのはstatは変わらないようになっています。
ラベル型をなぜか渡せないということにつまづきました。引き数情報(minfoに入っている)はちゃんとラベル型になっているのにエラーなります。
機械語部分のもとになったCのソースはコメントとしてつけたほうがいいでしょうか。



Noap

リンク

2015/12/10(Thu) 23:06:02|NO.73559

ecxレジスタの内容がわかる環境依存でthiscall対応のコールバックモジュールは
thiscallを使うことはないと思うので別のモジュールにしました

一覧に追加しました
http://nopswebpages.webcrow.jp/apps/ccallfn/

thiscallを使わないほうはすこし小さくなりました



ヒラギノ

リンク

2015/12/11(Fri) 00:07:43|NO.73561

こんな書き込みをするのは、とても恥ずかしいのですが、、、

コールバックモジュールを使うと、どんなことが出来るようになるのですか。。。



Noap

リンク

2015/12/13(Sun) 06:56:32|NO.73590

サンプルで挙げた EnumerateLoadedModules のようにコールバック関数が必要なAPIをHSPのスクリプトだけで呼び出せます。
またウィンドウプロシージャをHSPのスクリプトを書くだけで実現できます。
便利かどうかはよくわかりません。
モジュール内でウィンドウメッセージをモジュールで処理したいときに使えると思います。
説明がおかしければすみません。



Noap

リンク

2015/12/14(Mon) 22:02:54|NO.73611

tds12さんのモジュールはどのようなものだったのか見たくてこのモジュールを見たのですが
http://hsp.tv/play/pforum.php?mode=all&num=62130#68768

モジュール内変数であるthisptrではなくthisptrへのポインタ変数にecxレジスタをコピーしています
なのでthisポインタは取得できません
ただの私の勘違いであればごめんなさい



/*tds12さんのモジュールのコード*/ #include <stdarg.h> int __cdecl clbkfunc(int p1, ...){ int volatile temporary=0; int volatile argmax=0; int volatile counter; char * (__cdecl * volatile malloc)(int) = (char * (__cdecl *) (int))0x00000000; void (__cdecl * volatile free)(void *) = (void (__cdecl *) (void*))0x00000000; void (__cdecl * volatile hspfunc_call)(unsigned int) = (void (__cdecl *) (unsigned int))0x00000000; int * volatile p_p_this = (int *)0x00000000; int * volatile buffer=(int *)malloc(argmax<<2); int * volatile wparam = (int *)0x00000000; int ** volatile lparam= (int **)0x00000000; int * volatile stat = (int *)0x00000000; volatile va_list p_argument = (va_list)0x00000000; /*ここのこと ポインタ変数にecxを入れている モジュール内ではバッファ確保の前だけど変数宣言は関数の先頭でしないとだめなので後ろに持ってきた*/ asm mov p_p_this, ecx va_start(p_argument, p1); 0[buffer] = p1; for(counter=1; counter<argmax; counter+=1){ counter[buffer] = va_arg(p_argument, int); } *wparam=argmax; *lparam=buffer; hspfunc_call(0x00000000); temporary= *stat; va_end(p_argument); free(buffer); return temporary; }



tds12

リンク

2015/12/14(Mon) 23:37:18|NO.73613

> asm mov p_p_this, ecx
コンパイラが違うので、厳密な意味は分かりませんが、
ecxの中身をp_p_thisへ代入しているということでしょうか。
こちらのコンパイラでは、
>int volatile *_thisptr=(int*)0;
>__asm{
>mov [_thisptr],ecx
>}
となっていて、
ecxの中身を、hspモジュール内で静的な変数のポインタを代入した_thisptr
の指す先、つまり、hspモジュール内のthisptr変数へ、
代入しているつもりだったのですが、
自信はありません。

後日、気が向いたら、コールバックモジュールで作った関数ポインタを
thiscallで呼ぶ、関数を作り調べてみようと思います。

ちなみに、コンパイラは、Visual C++ 2008 Expressのコンパイラです。



Noap

リンク

2015/12/17(Thu) 23:14:55|NO.73641

(スクリプト中でtds12さんのコールバック関数作成モジュールに負数を渡していたのを修正しました)
(具体的な修正スクリプトを記載しました)
(それ以外は12/15の投稿とだいたい同じです)


しろうとなので何か間違えているかもしれません
間違えていたらごめんなさい。

ポインタの参照先のアドレスの数字があちこちに行かないようにしているのではなくて
ポインタ変数自体の最適化を抑止しているとは思いませんでした
(int * volatile _thisptr=(int*)0; ではなくて int volatile * _thisptr=(int*)0; であったということです)

またこの場合は



__asm{ mov eax, _thisptr mov [eax],ecx }

のようにするといいと思います
この_thisptrはレジスタ変数ではなくてスタック領域を使用しているためです([ebp-40]になります)


何か間違いがあればごめんなさい
ソースコードは何か間違いがあるかもしれません
わたしのかいたtds12さんのソースコードはだいたいあっていますか

具体的なスクリプト(マシン語部分のみ抜粋)にすると
引き数があるときは

dim clbk,58 clbk.0 = $83ec8b55, $45c730ec, $000000fc, $f845c700 clbk.4 = $00000000, $00e045c7, $c7000000, $0000e445 clbk.8 = $45c70000, $000000ec, $d845c700, $00000000 clbk.12 = $89d8458b, $f8458b08, $5002e0c1, $ffe04d8b clbk.16 = $04c483d1, $c7d44589, $0000f445, $45c70000 clbk.20 = $000000dc, $f045c700, $00000000, $00e845c7 clbk.24 = $8d000000, $55890c55, $d4458be8, $89084d8b clbk.28 = $d045c708, $00000001, $558b09eb, $01c283d0 clbk.32 = $8bd05589, $4539f845, $8b1a7dd0, $c183e84d clbk.36 = $e84d8904, $8bd0558b, $4d8bd445, $fc498be8 clbk.40 = $eb900c89, $f4558bd5, $89f8458b, $dc4d8b02 clbk.44 = $89d4558b, $00006811, $458b0000, $83d0ffec clbk.48 = $4d8b04c4, $89118bf0, $45c7fc55, $000000e8 clbk.52 = $d4458b00, $e44d8b50, $c483d1ff, $fc458b04 clbk.56 = $c25de58b, $00000000 lpoke clbk,$10,argmax:lpoke clbk,$17,ptrtomalloc:lpoke clbk,$1e,ptrtofree lpoke clbk,$25,code_callptr:lpoke clbk,$2c,varptr(thisptr) lpoke clbk,$4a,varptr(ctx) + 36:lpoke clbk,$51,varptr(ctx) + 40 lpoke clbk,$58,varptr(ctx) + 784:lpoke clbk,$b6,ilb if ((mode & $f) == CLBKMODE_CDECL) == 0:wpoke clbk,$e4,(argmax * 4) & $ffff funcsize = 230

引き数がないときは

dim clbk,25 clbk.0 = $83ec8b55, $45c718ec, $000000fc, $f045c700 clbk.4 = $00000000, $00f845c7, $c7000000, $0000e845 clbk.8 = $45c70000, $000000f4, $ec45c700, $00000000 clbk.12 = $89ec458b, $f8458b08, $000000c7, $4d8b0000 clbk.16 = $0001c7e8, $68000000, $00000000, $fff0558b clbk.20 = $04c483d2, $8bf4458b, $fc4d8908, $8bfc458b clbk.24 = $00c35de5 lpoke clbk,$10,code_callptr:lpoke clbk,$17,varptr(ctx) + 36 lpoke clbk,$1e,varptr(ctx) + 40:lpoke clbk,$25,varptr(ctx) + 784 lpoke clbk,$2c,varptr(thisptr):lpoke clbk,$48,ilb funcsize = 99
になります



わたしの実験

ecxレジスタに数字をいれられるcallfuncのようなモジュール
http://nopswebpages.webcrow.jp/apps/calfnc3.txt


tds12さんのモジュール

dim bin,5 newclbk3 bin.0,2,*raberu newclbk3 bin.1,0,*raberu newclbk3 bin.2,1,*raberu newclbk3 bin.3,0,*raberu newclbk3 bin.4,2,*raberu2 hikisuu=2,3 cls title "関数呼び出し2" mes "第2パラメータ(引き数の数)のテスト" foreach bin thisptr@modclbk3b2=111+cnt mes ""+cnt+"番の結果"+callfunc3(hikisuu,bin.cnt,2) loop stop *raberu mes "ecxレジスタ="+clbk_getthisptr()+" wparam="+wparam+" lparam="+lparam return 1192 *raberu2 mes "ecxレジスタ="+clbk_getthisptr() clbkargprotect funcargs thisptr@modclbk3b2=111 mes "サブルーチンの中からサブルーチンの呼び出し="+callfunc3(funcargs,bin.0,2,10) return 794


わたしのモジュール

dim bin,5 makeclbkfunc bin.0,2,*raberu makeclbkfunc bin.1,-1,*raberu makeclbkfunc bin.2,1,*raberu makeclbkfunc bin.3,0,*raberu makeclbkfunc bin.4,2,*raberu2 hikisuu=2,3 cls title "関数呼び出し2" mes "第2パラメータ(引き数の数)のテスト" foreach bin p_this@_modulemakeclbkfunca =111+cnt mes ""+cnt+"番の結果"+callfunc3(hikisuu,bin.cnt,2,2) loop stop *raberu mes "ecxレジスタ="+ecxclbkfunc()+" wparam="+wparam+" lparam="+lparam return 1192 *raberu2 argclbkfunc funcargs p_this@_modulemakeclbkfunca=123 mes "サブルーチンの中からサブルーチンの呼び出し="+callfunc3(funcargs,bin.0,2,10) return 794



ONION software Copyright 1997-2023(c) All rights reserved.