ウインドウプロシージャのように、HSP側から必要な情報を渡すことが出来ない関数があります。そのような関数で静的データやAPIを使用したい場合、アドレスの書き換え(リロケーション=再配置)を行う必要があります。ここではリロケーションの手間を最小限に押さえる方法を説明します。
サンプルとして、mesbox(エディットボックス)の色を変更するマシン語ファイルを作成します。
mesboxの色を変えるにはサブクラス化を行い、親ウインドウに送られるWM_CTLCOLOREDITメッセージにブラシのハンドルを返します。
APIのアドレスやブラシのハンドルなどはHSP側で用意します。
ファイル名:editcolor.c
#include <windows.h> //API関数ポインタの型定義 typedef COLORREF (WINAPI *SETBKCOLOR)(HDC,COLORREF); typedef COLORREF (WINAPI *SETTEXTCOLOR)(HDC,COLORREF); typedef LRESULT (WINAPI *CALLWINDOWPROC)(WNDPROC,HWND,UINT,WPARAM,LPARAM); //HSP側で用意するデータ typedef struct{ SETBKCOLOR pSetBkColor; //API関数ポインタ SETTEXTCOLOR pSetTextColor; // 〃 CALLWINDOWPROC pCallWindowProc; // 〃 WNDPROC pPrevWndProc; //元のウインドウプロシージャ HBRUSH hBrush; //背景を描くブラシのハンドル COLORREF bkcolor; //文字の背景色 COLORREF textcolor; //文字の色 } hspstruct; LRESULT CALLBACK WindowProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam) { hspstruct * volatile pHspdata=(hspstruct*)0xeeeeeeee; //この部分のコードを書き換える hspstruct *pData=pHspdata; switch(uMsg){ case WM_CTLCOLOREDIT: pData->pSetBkColor((HDC)wParam,pData->bkcolor); pData->pSetTextColor((HDC)wParam,pData->textcolor); return (LRESULT)(pData->hBrush); default: return pData->pCallWindowProc(pData->pPrevWndProc,hwnd,uMsg,wParam,lParam); } }
必要なデータは構造体にまとめておき、一度だけ構造体へのポインタを受け取るようにします。こうすることで書き換える位置を一カ所だけにすることが出来ます。
(hspstruct*)0xeeeeeeee は構造体の仮のアドレスで、後で書き換える場所の目印となります。
構造体のアドレスはvolatile変数に格納します。
こうしないと、コンパイラが仮のアドレスを使った最適化を行うため、意図しない影響を受けてしまいます。
その後volatile変数をそのまま使うわけにはいかないので、通常の変数にコピーして使うようにします。
マシン語ファイルの作成方法は前回と同じです。
作成されたEDITCOLOR.BINをバイナリエディタなどでダンプ表示すると以下のようになります。
+0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F
00000000 55 8B EC 51 53 56 57 8B-75 10 8B 45 0C C7 45 FC |U駆QSVW丘.畿.ヌE
00000010 EE EE EE EE 8B 5D FC 8B-D0 81 EA 33 01 00 00 75 |~犠巾3...u
00000020 16 8B 43 14 8B FE 50 57-FF 13 8B 43 18 50 57 FF |.気...PW..気.PW.
00000030 53 04 8B 43 10 EB 11 8B-55 14 52 56 50 8B 4D 08 |S.気...偽.RVP貴.
00000040 51 8B 43 0C 50 FF 53 08-5F 5E 5B 59 5D C2 10 00 |Q気.P.S._^[Y]ツ..
ソースファイルで定義した0xEEEEEEEEが見えていますので、リロケートする位置は0x00000010ということが分かります。
この部分をHSP側で書き換えます。
もし該当箇所が複数ある時はソースファイルの値を適当な値に変えてからもう一度マシン語ファイルを作成してください。
マシン語ファイルの使用例
WA_MACROを使用しています。
#include "wam/winapi.as" #define GWL_WNDPROC $FFFFFFFC #define BS_SOLID $00000000 textcolor=$ff00ff ;文字の色 bkcolor=$ffffcc ;背景の色 relocpos=$10 ;リロケーション位置 ;マシン語ファイルを読み込む filename="editcolor.bin" exist filename if strsize==-1:dialog filename+"がみつかりません。":end sdim func,strsize bload filename,func ;マシン語で使用するAPI ll_getproc pSetBkColor,"SetBkColor",hdll_GDI32 ll_getproc pSetTextColor,"SetTextColor",hdll_GDI32 ll_getproc pCallWindowProc,"CallWindowProcA",hdll_USER32 ;元のウインドウプロシージャ GetWindowLong PRMHWND,GWL_WNDPROC pPrevWndProc=dllret ;エディットボックスの背景を描くブラシ logbrush=BS_SOLID,bkcolor,0 CreateBrushIndirect ptr(logbrush) hBrush=dllret ;必要なデータを配列にまとめる hspdata=pSetBkColor,pSetTextColor,pCallWindowProc,pPrevWndProc,hBrush,bkcolor,textcolor ;リロケーション getaddr pHspdata,hspdata memcpy func,pHspdata,4,relocpos sdim s,256 mesbox s,640,480,1 idMesBox=stat ;サブクラス化 SetWindowLong PRMHWND,GWL_WNDPROC,ptr(func) ;エディットボックスの再描画を指示 InvalidateRect PRMHOBJ(idMesBox),NULL,TRUE stop