UWSCのみでFUKIDASIをカラフルにする
DLLを使わずXP対応した、カラフルFUKIDASI決定版。
いやはや、可能だったとは、、、。
スクリプト
一応、Asmモジュールもつけてますが、
UWSCにできないことはない? - じゅんじゅんのきまぐれ
と同じなので、それのインクルード(CALL)でも可。
OPTION EXPLICIT DIM fcs[] = $FF0000, $C00040, $800080, $4000C0, $0000FF DIM msg="吹き<#CR>出しで", bc=$00FF00, al=0 Fukidashi.Show(fcs, msg, G_MOUSE_X, G_MOUSE_Y, 0, 16, "MS ゴシック", bc, al) MSGBOX("OK?") Fukidashi.Show(fcs, msg, G_MOUSE_X, G_MOUSE_Y, 1, 32, "MS Pゴシック", bc, al) MSGBOX("OK?") Fukidashi.Show(fcs, msg, G_MOUSE_X, G_MOUSE_Y, 2, 8, "MS P明朝", bc, al) MSGBOX("OK?") Fukidashi.Show(fcs, msg, G_MOUSE_X, G_MOUSE_Y, 3, 10, "MS 明朝", bc, al) MSGBOX("OK?") Fukidashi.Show(fcs, msg, G_MOUSE_X, G_MOUSE_Y, 4, 72, "MS ゴシック", bc, al) MSGBOX("OK?") Fukidashi.Dispose() // 使い終わったら必ず必要 MODULE Fukidashi DIM _loop, _addr, _para, _event, _hwnd // FUKIDASIとほぼ同じ引数。テキスト色が配列で先頭で省略不可 PROCEDURE Show(fcs[], msg=EMPTY, x=0, y=0, dir=0, pt=10, font="MS Pゴシック", bc=$FFFF, al=0) DIM fc = 0, fcnum = LENGTH(fcs) IF fcnum > 0 THEN fc = fcs[fcnum-1] IFB _hwnd THEN FUKIDASI() _loop = FALSE SLEEP(0.01) WHILE !_loop SLEEP(0.01) WEND ENDIF FUKIDASI(msg, x, y, dir, pt, font, fc, bc, al) IF LENGTH(msg) THEN THREAD _Hook(fcs, msg, x, y, dir, pt, font, bc, al) FEND PROCEDURE Fukidashi DEF_DLL CreateEventA(DWORD,bool,bool,string): DWORD: kernel32 _loop = TRUE _hwnd = 0 DIM code = "VYvsUYtFCIlF/ItN/IN5IAB1IotV/IN6FAB0GYtF/IPAMFBqAGoCi038i1EU/9KLTfyJQSCL" code = code + "VfyDeiAAdSSLRfyDeBAAdBuLTfyDwTBRagBqAGoAi1X8i0IQ/9CLTfyJQSCLVfyLQghQavyL" code = code + "TfyLUQRSi0X8iwj/0YtV/IlCDItF/ItADIvlXcIEAMzMzMzMVYvsUYtFCIlF/ItN/ItRDFJq" code = code + "/ItF/ItIBFGLVfyLAv/Qi038iUEIi1X8g3okAHQVagBqAGoAi0X8i0gEUYtV/ItCJP/Qi038" code = code + "g3kgAHQYi1X8g3ocAHQPi0X8i0ggUYtV/ItCHP/Qi038i0EIi+VdwgQAzMzMzMzMzMzMzMzM" code = code + "zMxVi+xRx0X8EREREYtF/ItNDDtILHUhi1X8g3oYAHQYi0X8g3ggAHQPi038i1EgUotF/ItI" code = code + "GP/Ri1UUUotFEFCLTQxRi1UIUotF/ItIDFGLVfyLQij/0IvlXcIQAMzMzMw=" Asm.Asm // 何故か初期化されないので入れとく _addr = Asm.Set(code) _para = Asm.Alloc(80) DIM eventName = "JuneColorFukidashiEvent", i = 0 IFB _addr > 0 AND _para > 0 THEN Asm.SetDword(_addr + $117, _para) i = i + Asm.SetDword(_para + i, Asm.GetProcAddress(Asm.hU32, "SetWindowLongA")) i = i + 4 // hWnd i = i + Asm.SetDword(_para + i, _addr + $110) i = i + 8 i = i + Asm.SetDword(_para + i, Asm.GetProcAddress(Asm.hK32, "OpenEventA")) i = i + Asm.SetDword(_para + i, Asm.GetProcAddress(Asm.hK32, "SetEvent")) i = i + Asm.SetDword(_para + i, Asm.GetProcAddress(Asm.hK32, "CloseHandle")) i = i + 8 //i = i + Asm.SetDword(_para + i, Asm.GetProcAddress(Asm.hU32, "SendMessageA")) i = i + Asm.SetDword(_para + i, Asm.GetProcAddress(Asm.hU32, "CallWindowProcA")) i = i + Asm.SetDword(_para + i, $85) // WM_NCPAINT i = i + Asm.SetString(_para + i, eventName) ENDIF _event = CreateEventA(0, FALSE, FALSE, eventName) FEND PROCEDURE Dispose() IFB _hwnd THEN DIM fcs[] = 0 Show(fcs) DIM i = 0, res = Asm.Run(_addr + $90, _para, i) ENDIF IF _para THEN Asm.Free(_para) IF _addr THEN Asm.Free(_addr) IF _event THEN Asm.CloseHandle(_event) FEND PROCEDURE _Hook(fcs[], msg, x, y, dir, pt, font, bc, al) _Paint(fcs, msg, x, y, dir, pt, font, bc, al) DIM res = 0, i = 0 IFB _hwnd = 0 AND _para > 0 THEN _hwnd = IDTOHND(GETID(GET_FUKIDASI_WIN)) Asm.SetDword(_para + 4, _hwnd) res = Asm.Run(_addr, _para, i) ENDIF WHILE _loop res = Asm.WaitForSingleObject(_event, 10) IFB res = 0 THEN _Paint(fcs, msg, x, y, dir, pt, font, bc, al) ENDIF WEND _loop = TRUE FEND PROCEDURE _Paint(fcs[], msg, x, y, dir, pt, font, bc, al) // WIN32API // テキスト描画用 DEF_DLL GetDC(hwnd): uint: user32 DEF_DLL ReleaseDC(hwnd, dword): int: user32 DEF_DLL DrawTextW(dword, wstring, int, {long, long, long, long}, uint): int: user32 // テキストフォント変更用 DEF_DLL SelectObject(dword, dword): dword: gdi32 DEF_DLL DeleteObject(dword): bool: gdi32 DEF_DLL CreateFontW(int, int, int, int, int, dword, dword, dword, dword, dword, dword, dword, dword, wstring): dword: gdi32 DEF_DLL GetDeviceCaps(dword, int): int: gdi32 DEF_DLL MulDiv(int, int, int): int: kernel32 // 文字色・背景色変更 DEF_DLL SetTextColor(dword, dword): dword: gdi32 DEF_DLL SetBkColor(dword, dword): dword: gdi32 DEF_DLL SetBkMode(dword, int): int: gdi32 // とりあえずFUKIDASI出して情報収集 DIM wid = GETID(GET_FUKIDASI_WIN) DIM hwndF = IDTOHND(wid) DIM hdcF = GetDC(hwndF) DIM l = 0, t = 0, r = STATUS(wid, ST_CLWIDTH), b = STATUS(wid, ST_CLHEIGHT) // 微調整 SELECT dir CASE 1 t = 5; b = b + t CASE 2 b = b - 10 CASE 3 l = 5; r = r + l CASE 4 r = r - 10 SELEND // フォント作成とフォント・色設定 DIM ro = r, bo = b, nHeight = MulDiv(pt, GetDeviceCaps(hdcF, 90), 72) DIM hfontF = CreateFontW(0 - nHeight, 0, 0, 0, 0, FALSE, FALSE, FALSE, 0, 0, 0, 0, 0, font) DIM hfontO = SelectObject(hdcF, hfontF) DIM cFr = SetTextColor(hdcF, 0) DIM cBk = SetBkColor(hdcF, bc) DIM cBf = FALSE, cBt IFB al < 0 THEN cBf = TRUE cBt = SetBkMode(hdcF, 1) ENDIF // 描画位置を特定する DIM off = DrawTextW(hdcF, msg, LENGTH(msg), l, t, r, b, $400) l = l + (ro - r) / 2; r = (ro + r) / 2; ro = r t = t + (bo - b) / 2; b = (bo + b) / 2 // 一文字づつ描く DIM fcnum = LENGTH(fcs) DIM msgnum = LENGTH(msg), i, tar, lo = l, s = -1 FOR i = 1 TO msgnum tar = COPY(msg, i, 1) IFB tar = CHR(10) THEN t = t + nHeight l = lo s = s - 1 CONTINUE ELSEIF tar = CHR(13) THEN s = s - 1 CONTINUE ENDIF IFB fcnum > i + s THEN SetTextColor(hdcF, fcs[i+s]) ELSE BREAK ENDIF off = DrawTextW(hdcF, tar, 1, l, t, r, b, $400) off = DrawTextW(hdcF, tar, 1, l, t, r, b, 0) // 次の文字の準備 l = r; r = ro NEXT // 後片付け SelectObject(hdcF, hfontO) DeleteObject(hfontF) SetTextColor(hdcF, cFr) SetBkColor(hdcF, cBk) IF cBf THEN SetBkMode(hdcF, cBt) ReleaseDC(hwndF, hdcF) FEND ENDMODULE MODULE Asm DEF_DLL GetLastError(): DWORD: kernel32 DEF_DLL VirtualAlloc(DWORD, DWORD, DWORD, DWORD): DWORD: kernel32 DEF_DLL VirtualFree(DWORD, DWORD, DWORD): bool: kernel32 DEF_DLL GetModuleHandleA(string): DWORD: kernel32 DEF_DLL GetProcAddress(DWORD, string): DWORD: kernel32 DEF_DLL CreateThread(DWORD, DWORD, DWORD, DWORD, DWORD, DWORD): DWORD: kernel32 DEF_DLL WaitForSingleObject(DWORD, DWORD): DWORD: kernel32 DEF_DLL CloseHandle(DWORD): bool: kernel32 DEF_DLL GetExitCodeThread(DWORD, var DWORD): bool: kernel32 PUBLIC hK32 PUBLIC hU32 PROCEDURE Asm hk32 = GetModuleHandleA("kernel32") hU32 = GetModuleHandleA("user32") FEND FUNCTION Set(code) DIM dom = CreateOleObj("Microsoft.XMLDOM") DIM binMan = dom.createElement("tmp") binMan.dataType = "bin.base64" binMan.text = code DIM i = LENGTH(code), size = i * 3 / 4 IFB i > 3 THEN IF COPY(code, i-1, 1) = "=" THEN size = size - 1 IF COPY(code, i, 1) = "=" THEN size = size - 1 ENDIF DIM data[size-1], b = binMan.nodeTypedValue FOR i = 0 TO size - 1 data[i] = b[i] NEXT RESULT = VirtualAlloc(0, size, $1000, $40) IF RESULT THEN SetByte(RESULT, data) FEND FUNCTION Alloc(size) RESULT = VirtualAlloc(0, size, $1000, $4) FEND FUNCTION Free(addr) RESULT = VirtualFree(addr, 0, $8000) FEND // 戻りはtypeによって異なる // type=0 : スレッド終了コード // type=1 : スレッド終了コード取得失敗エラーコード // type=258 : スレッドハンドル // type=他 : その他エラーコード FUNCTION Run(addr, para, var type, timeout=$7FFFFFFF) DIM hThread = CreateThread(0, 0, addr, para, 0, 0), res = 0 RESULT = GetLastError() type = 258 IF timeout >= 0 THEN type = WaitForSingleObject(hThread, timeout) SELECT type CASE 0 IFB GetExitCodeThread(hThread, res) THEN RESULT = res ELSE type = 1 RESULT = GetLastError() ENDIF CloseHandle(hThread) CASE 258 RESULT = hThread SELEND FEND FUNCTION SetByte(p, data[]) DEF_DLL RtlMoveMemory(DWORD, BYTE[], DWORD): kernel32 RESULT = LENGTH(data) RtlMoveMemory(p, data, RESULT) FEND FUNCTION SetDword(p, data) DEF_DLL RtlMoveMemory(DWORD, var DWORD, DWORD): kernel32 RESULT = 4 RtlMoveMemory(p, data, RESULT) FEND FUNCTION SetString(p, data) DEF_DLL RtlMoveMemory(DWORD, string, DWORD): kernel32 RESULT = LENGTHB(data) RtlMoveMemory(p, data, RESULT) FEND PROCEDURE Dump(addr, size) DEF_DLL RtlMoveMemory(BYTE[], DWORD, DWORD): kernel32 DIM data[size], i, buf = "", bufa = "" RtlMoveMemory(data, addr, size) FOR i = 0 TO size - 1 buf = buf + FORMAT(data[i], 3, -1) IFB data[i] >= $20 AND data[i] < $7F THEN bufa = bufa + CHR(data[i]) ELSE bufa = bufa + "." ENDIF IFB i MOD 16 = 15 THEN PRINT buf + " " + bufa buf = "" bufa = "" ENDIF NEXT IF LENGTH(buf) THEN PRINT buf + FORMAT(" ", 49 - LENGTH(buf)) + bufa FEND ENDMODULE
もう、
UWSCのFUKIDASIをカラフルにする - じゅんじゅんのきまぐれ
も
UWSCのFUKIDASIを多色にする - じゅんじゅんのきまぐれ
もいらんね。
後者はシンプルなので、あっても良いかもしれないけど。
応用のためのヒント
Fukidashiモジュール初期化処理でごちゃごちゃ設定してるように、
- Asm.Run(_addr, _para, i) で、WndProcをフック
- _para+4の位置にフック対象のHWNDを指定
- Asm.SetString(_para + i, eventName) で設定するイベントを開く
- もとのWndProcは、_para+12にある
- 新しいWndProcは、「i = i + Asm.SetDword(_para + i, $85) // WM_NCPAINT」とあるように、WM_NCPAINTが来たら、SetEventしている
- そしてもとのWndProcを呼び出す
- Asm.Run(_addr+$90, _para, i)で、WndProcフック解除
- FUKIDASIの場合不要みたいなので解除後のSendMessage(WM_NULL)は無効化している
さてー、これで何に応用できますかね?