目次
ここにはウィンドウに関するプログラムのコードを載せています。
| 1 | クライアント領域を拡張する |
|---|---|
| 2 | ウィンドウハンドルからプロセスのファイルパスを取得する(64bit対応) |
1.クライアント領域を拡張する
ソースコード
ウィンドウのクライアント領域を拡張します。タイトルバーの部分に描画したり、GUIオブジェクトを設置したりすることができるようになります。 以下にプログラムの流れを示します。
1. GetSystemMetricsa で各種情報を取得する。
2. NCCALCSIZE メッセージを常に監視し、領域を変更する。
3. DwmExtendFrameIntoClientArea でクライアント領域を設定する。
4. SetWindowPos で座標を(0,0)にする。
5.それ以降のウィンドウ移動、リサイズは SetWindowPos で行う。
2. NCCALCSIZE メッセージを常に監視し、領域を変更する。
3. DwmExtendFrameIntoClientArea でクライアント領域を設定する。
4. SetWindowPos で座標を(0,0)にする。
5.それ以降のウィンドウ移動、リサイズは SetWindowPos で行う。
このソースコードでは一連の動作をモジュール化しました。ソフトウェアに簡単に組み込めるようになっています。
/*-------------------- ここからモジュール --------------------*/
#module
#define WM_NCCALCSIZE $00000083
#define SM_CXSIZEFRAME $00000020
#define SM_CYSIZEFRAME $00000021
#define ctype GetWinLR ( ( ginfo(6) - ginfo(4) - ginfo(12) ) / 2 )
#define ctype GetCaptionSize ( ginfo(7) - ginfo(5) - ginfo(13) - GetWinLR()*2 )
#uselib "user32.dll"
#func global SetWindowPos "SetWindowPos" int, int, int, int, int, int, int
#cfunc GetSystemMetrics "GetSystemMetrics" sptr
#uselib "dwmapi.dll"
#func DwmExtendFrameIntoClientArea "DwmExtendFrameIntoClientArea" int, int
// ExpClientArea ... ウィンドウのクライアント領域を拡張する
#deffunc ExpClientArea
dim rect, 4 : lx = 0 : ly = 0 : titY = 0
// ウィンドウの各領域のサイズを取得
lx = GetSystemMetrics( SM_CXSIZEFRAME ) ; 左右の領域
ly = GetSystemMetrics( SM_CYSIZEFRAME ) ; 下の領域
titY = GetCaptionSize() ; タイトルバーの領域
// 監視
oncmd gosub *CMD_NCCALCSIZE, WM_NCCALCSIZE
// 領域を指定
rect = lx, lx, titY, ly/2 ; それぞれ 左, 右, 上, 下 からの領域
DwmExtendFrameIntoClientArea hwnd, varptr(rect)
// 描画の更新処理
SetWindowPos hwnd, 0, 0, 0, ginfo(12), ginfo(13), 0
color : boxf
return titY
// NCCALCSIZEメッセージ監視用ラベル
*CMD_NCCALCSIZE
if lParam {
dupptr NCCALCSIZE_PARAMS, lparam, 16
// ここで描画領域を指定します
NCCALCSIZE_PARAMS(0) -= lx ;left
NCCALCSIZE_PARAMS(1) -= titY ;top
NCCALCSIZE_PARAMS(2) += lx ;right
NCCALCSIZE_PARAMS(3) += 0 ;bottom
}
return
#global
/*-------------------- ここまでモジュール --------------------*/
screen 0, 640, 480, 4 : title "Sample"
// クライアント領域を拡張
ExpClientArea : cpsize = stat
// 必ずSetWindowPos等で再描画せずに移動すること
SetWindowPos hwnd, 0, ginfo(20)/2 - 320, ginfo(21)/2 - 240, 640, 480, 0
// クライアント領域に描画
color 255 : pos 4, 4 : font MSMincho, 14, 1
mes "クライアント領域に描画します。"
mes "\n実際にはGDI+等を使用することでクライアント領域への描画の半透明化を防ぎます。"
mes "\nboxfなどでクライアント領域部分まで塗りつぶさないように注意してください。"
// ウィンドウ移動用
onclick gosub *MoveWindow
stop
// ウィンドウを移動
*MoveWindow
;if ginfo(2) == 0 { ; ウィンドウIDが 0 のときのみ
if mousey <= cpsize {
sendmsg hwnd, $a1, 2
}
;}
return
ExpClientArea を呼び出した後のウィンドウ移動、リサイズは必ず SetWindowPos で行うことに注意してください。また、その際に再描画フラグを入れてはいけません。(表示がおかしくなるので)
追記(2015-12-04) : 一部環境では正しく実行されません
参考文献
Firefoxボタンの謎 : 傾き指向プログラミング
SetWindowPos 関数
ウィンドウ枠の拡張 - HSPTV!掲示板
2.ウィンドウハンドルからプロセスのファイルパスを取得する(64bit対応)
ソースコード
ウィンドウハンドルからそのプログラムの実行ファイル名を取得します。HSPは32bitなので、そこから呼び出したGetModuleFileNameExは64bitのプログラムに対して失敗してしまいます。 このコードでは64bitプログラム及びドライバ名(\~)に対応しています。 このコードについては、こちらのスレッドで指摘していただきました。 多くのサイトでは従来(32bitのみ対応)の方法で説明しているようなので、ここで紹介させていただきます。以下にプログラムの流れを示します。
1. GetWindowThreadProcessId でスレッドID及びプロセスIDを取得する。
2. OpenProcess でプロセスハンドルを取得する。
3. GetProcessImageFileName でファイルパスを取得する。
4. CloseHandle でプロセスを閉じる。
5.デバイス名をドライブ上のパスに変換する。
2. OpenProcess でプロセスハンドルを取得する。
3. GetProcessImageFileName でファイルパスを取得する。
4. CloseHandle でプロセスを閉じる。
5.デバイス名をドライブ上のパスに変換する。
このソースコードでは一連の動作をモジュール化しました。ソフトウェアに簡単に組み込めるようになっています。
/*-------------------- ここからモジュール --------------------*/
#module
#define PROCESS_ALL_ACCESS $001F0FFF
#uselib "user32.dll"
#cfunc IsWindow "IsWindow" int
#cfunc GetWindowThreadProcessId "GetWindowThreadProcessId" int, int
#uselib "psapi.dll"
#func GetProcessImageFileName "GetProcessImageFileNameA" int, int, int
#uselib "kernel32.dll"
#cfunc OpenProcess "OpenProcess" int, int, int
#func CloseHandle "CloseHandle" int
#cfunc GetLogicalDrives "GetLogicalDrives"
#func QueryDosDeviceA "QueryDosDeviceA" sptr, var, int
// ウィンドウハンドルからファイルパスを取得
// p1 : ウィンドウハンドル
// [返り値] ファイルパス=成功 / 空=失敗
#defcfunc GetFilePath int hwnd_
if IsWindow(hwnd_) == 0 : return ""
ProcessID = 0 : sdim FilePath, 256
// ドライブ名を配列化
GetAllDrive LDNL, DNL
// スレッドIDとプロセスIDを取得
ThreadID = GetWindowThreadProcessId( hwnd_, varptr(ProcessID) )
// プロセスハンドルを取得
hProcess = OpenProcess( PROCESS_ALL_ACCESS, 1, ProcessID )
// ファイルパスを取得(この時点では \* の可能性あり)
GetProcessImageFileName hProcess, varptr(FilePath), 256
// プロセスを閉じる
CloseHandle hProcess
// デバイス名をドライブ名に変換
DeviceToDrive FilePath, LDNL, DNL
return FilePath
// 論理ドライブ名を全て取得
#deffunc GetAllDrive array LDNL_, array DNL_
count = 0 : sdim buf, 64
sdim LDNL_, 64, 26 : sdim DNL_, 256, 26
// 利用可能なディスクを取得
BitMask = GetLogicalDrives()
repeat 26
// ビットマスク形式を調査
// (例)1100 : C, Dドライブ 1001 : A, Dドライブ
if BitMask & 1 << cnt {
// $3A41 + cnt で[A:]~[Z:]の文字コードを書き込む
wpoke LDNL_(cnt), 0, 14913 + cnt
QueryDosDeviceA LDNL_(cnt), DNL_(cnt), 256
count++
}
loop
return count
// デバイス名をドライブ名に変換
#deffunc DeviceToDrive var dName, array LDNL_, array DNL_
repeat 26
if instr( dName, 0, DNL_(cnt) ) == 0 {
tmp1 = strlen(dName)
tmp2 = strlen(DNL_(cnt))
dName = LDNL_(cnt) + strmid( dName, tmp2, tmp1 - tmp2 )
break
}
loop
return
#global
/*-------------------- ここまでモジュール --------------------*/
screen 0, 640, 480, 4 : title "Sample"
// ウィンドウハンドルからファイルパスを取得
mes GetFilePath(hwnd)
stop
参考文献