外部変数を利用する方法

こちらの方が、少しだけ効率のよいコードを出力できます。


ファイル名: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)
{
    extern hspstruct * volatile pHspdata; //外部変数
    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);
    }
}

外部のポインタから値を受け取ることで、仮アドレスによる意図しない影響を受けないようにします。(volatileも念のために付けておきます。)
外部変数を使用するようにしたため、それを記述したソースファイルが必要になります。
これはアセンブリファイルで用意します。


ファイル名:subfile.asm

.386
.model tiny,C
externdef pHspdata:ABS
pHspdata equ 0eeeeeeeeh
END

名前がpHspdataで値が0xEEEEEEEEのシンボルを、外部ファイルから見えるように定義しています。
CのソースファイルではpHspDataは(hspstruct *)型の変数ですが、このファイルでは任意の値を指定できるように定数にしています。この定数の型は(hspstruct**)になります。
シンボル名や値を変更するときは赤字部分を変更してください

subfile.asmをソースと同じフォルダに置いて、以下のバッチファイルを実行することでマシン語ファイル(拡張子 BIN)を作成できます。
LINK : warning L4055: start address not equal to 0x100 for /TINY
という警告が出ますが気にしないでください。
IDEを使用する場合はこちら。


ソースのファイル名拡張子VC++のインストール先を赤字部分に設定してください。
OSが Win9x,Meの場合はバッチファイルの「プロパティ」->「メモリ」->「環境変数の初期サイズ」を1024以上にしてください。

@SET file=editcolor
@SET ext=c
@echo off
:コマンドライン用環境設定ファイル(VC++インストール時に作成されている)
call "C:\Program Files\Microsoft Visual Studio\VC98\Bin\VCVARS32.BAT"
cl /c /FA /O2 /Fonul %file%.%ext%
if errorlevel 1 goto error
ml /c /Cp %file%.asm subfile.asm
if errorlevel 1 goto error
link16 /TINY /NODEFAULTLIBRARYSEARCH /NOIGNORECASE %file%.obj subfile.obj,%file%.bin,nul,,,
if errorlevel 1 goto error
echo =====================作成成功==========================
goto fin
:error
echo =====================エラー========================
if exist %file%.bin del %file%.bin
:fin
if exist %file%.asm del %file%.asm
if exist %file%.obj del %file%.obj
if exist subfile.obj del subfile.obj
if "%OS%"=="Windows_NT" pause>nul

IDEを使用する場合はsubfile.asmの設定で「このファイルをビルドしない」にチェックを入れてから、ソースファイルのカスタムビルド設定で以下のコマンドを入力します。

cl /c /FA /Fonul /Fa$(IntDir)\ /O2 $(InputPath)
if errorlevel 1 goto error
ml /c /Cp /Fo$(IntDir)\ $(IntDir)\$(InputName).asm $(InputDir)\subfile.asm
if errorlevel 1 goto error
link16 /TINY /NODEFAULTLIBRARYSEARCH /NOIGNORECASE $(IntDir)\$(InputName).obj $(IntDir)\subfile.obj, $(TargetDir)\$(InputName).bin,nul,,,
if errorlevel 1 goto error
echo =====================作成成功==========================
goto fin
:error
echo =====================エラー========================
if exist $(TargetDir)\$(InputName).bin del  $(TargetDir)\$(InputName).bin
:fin


作成されたEDITCOLOR.BINをバイナリエディタなどでダンプ表示すると以下のようになります。

          +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F
00000000  8B 44 24 08 56 8B 35 EE-EE EE EE 3D 33 01 00 00 |汽$.V.5・・=3...
00000010  74 1B 8B 4C 24 14 8B 54-24 10 51 8B 4E 0C 52 50 |t.記$.亀$.Q起.RP
00000020  8B 44 24 14 50 51 FF 56-08 5E C2 10 00 8B 56 14 |汽$.PQ.V.^ツ..儀.
00000030  57 8B 7C 24 14 52 57 FF-16 8B 46 18 50 57 FF 56 |W弓$.RW..祈.PW.V
00000040  04 8B 46 10 5F 5E C2 10-00 00 00 00             |.祈._^ツ.....

ソースファイルで定義した0xEEEEEEEEが見えていますので、リロケートする位置は0x00000007ということが分かります。
この部分をHSP側で書き換えます。
もし該当箇所が複数ある時はソースファイルの値を適当な値に変えてからもう一度マシン語ファイルを作成してください。


マシン語ファイルの使用例
WA_MACROを使用しています。

#include "winapi.as"
#define GWL_WNDPROC     $FFFFFFFC
#define BS_SOLID        $00000000

textcolor=$ff00ff       ;文字の色
bkcolor=$ffffcc         ;背景の色
relocpos=7              ;リロケーション位置

;マシン語ファイルを読み込む
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 ppHspdata,pHspdata
memcpy func,ppHspdata,4,relocpos


sdim s,256
mesbox s,640,480,1
idMesBox=stat

;サブクラス化
SetWindowLong PRMHWND,GWL_WNDPROC,ptr(func)

;エディットボックスの再描画を指示
InvalidateRect PRMHOBJ(idMesBox),NULL,TRUE

stop 

戻る