コールバック関数のようにHSP側から引数を渡すことが出来ない場合、リロケーション(再配置)が必要となります。ここではそのための方法を説明します。
サンプルとして、mesbox(エディットボックス)の色を変更するマシン語ファイルを作成します。
エディットボックスの色を変えるにはサブクラス化を行い、親ウインドウに送られるWM_CTLCOLOREDITメッセージにブラシのハンドルを返します。
APIのアドレスやブラシのハンドルなどはHSP側で用意します。
ファイル名:EDITCOLOR.ASM
.386 .MODEL TINY,STDCALL OPTION SEGMENT:USE32,CASEMAP:NONE include windows.inc ;API関数ポインタの型定義 _SETBKCOLOR typedef proto ,:HDC,:COLORREF _SETTEXTCOLOR typedef proto ,:HDC,:COLORREF _CALLWINDOWPROC typedef proto ,:WNDPROC,:HWND,:UINT,:WPARAM,:LPARAM SETBKCOLOR typedef ptr _SETBKCOLOR SETTEXTCOLOR typedef ptr _SETTEXTCOLOR CALLWINDOWPROC typedef ptr _CALLWINDOWPROC ;HSP側から渡されるデータの内容 hspstruct struct _SetBkColor SETBKCOLOR ? _SetTextColor SETTEXTCOLOR ? _CallWindowProc CALLWINDOWPROC ? pPrevWndFunc WNDPROC ? ;元のウインドウプロシージャ hBrush HBRUSH ? ;背景を描くブラシのハンドル bkcolor COLORREF ? ;文字の背景色 textcolor COLORREF ? ;文字の色 hspstruct ends .CODE ;リロケーションを行う ;引数:HSP側で用意したデータのアドレス ;返値:ウインドウプロシージャのアドレス init PROC pHspdata:ptr hspstruct mov ecx,pHspdata call l1 l1: pop eax ;l1のアドレスを取得 sub eax,l1 ;実際のアドレスと仮アドレスの差を求める mov [reloc-4+eax],ecx ;コードを書き換える lea eax,[WindowProc+eax] ;WindowProcのアドレスを返す ret init ENDP ;新しいウインドウプロシージャ WindowProc PROC USES ebx,hwnd:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM mov ebx,0 ;mov ebx,pHspdata reloc:: ;reloc-4がリロケートするオフセット位置になる ASSUME ebx:ptr hspstruct ;ebxの型をアセンブラに通知 .if uMsg==WM_CTLCOLOREDIT invoke [ebx]._SetBkColor,wParam,[ebx].bkcolor invoke [ebx]._SetTextColor,wParam,[ebx].textcolor mov eax,[ebx].hBrush .else invoke [ebx]._CallWindowProc,[ebx].pPrevWndFunc,hwnd,uMsg,wParam,lParam .endif ret WindowProc ENDP END init
HSP側で用意するデータは構造体にまとめておくことで、リロケーション位置を一カ所に出来ます。
初期化関数を作り、そこでリロケーションを行います。
具体的なリロケーション位置は、「次の命令のアドレス−4」になることが多いです。(もちろん命令によって違います)
以下のコマンドを実行することで、マシン語ファイル(EDITCOLOR.BIN)が作成されます。
ml /AT /Bllink16 /FeEDITCOLOR.BIN EDITCOLOR.ASM
マシン語ファイルの使用例
WA_MACROを使用しています。
#include "wam/winapi.as" #define GWL_WNDPROC $FFFFFFFC #define BS_SOLID $00000000 textcolor=$ff00ff ;文字の色 bkcolor=$ffffcc ;背景の色 ;マシン語ファイルを読み込む filename="editcolor.bin" exist filename if strsize==-1:dialog filename+"がみつかりません。":end sdim func,strsize bload filename,func ;マシン語で使用するAPI ll_getproc lpSetBkColor,"SetBkColor",hdll_GDI32 ll_getproc lpSetTextColor,"SetTextColor",hdll_GDI32 ll_getproc lpCallWindowProc,"CallWindowProcA",hdll_USER32 ;元のウインドウプロシージャ GetWindowLong PRMHWND,GWL_WNDPROC : lpPrevWndProc=dllret ;エディットボックスの背景を描くブラシ logbrush=BS_SOLID,bkcolor,0 CreateBrushIndirect ptr(logbrush) : hBrush=dllret ;必要なデータを配列にまとめる hspdata=lpSetBkColor,lpSetTextColor,lpCallWindowProc,lpPrevWndProc,hBrush,bkcolor,textcolor ;ウインドウプロシージャのアドレスを取得 getaddr pHspdata,hspdata getaddr pFunc,func ll_callfunc pHspdata,1,pFunc lpWndProc=dllret sdim s,256 mesbox s,640,480,1 idMesBox=stat ;サブクラス化 SetWindowLong PRMHWND,GWL_WNDPROC,lpWndProc ;エディットボックスの再描画を指示 InvalidateRect PRMHOBJ(idMesBox),NULL,TRUE stop