Borland C++ Compiler 5.5(BCC)でマシン語ファイルを作成

その2:ウインドウプロシージャの作成

ウインドウプロシージャのように、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 

次へ