goo blog サービス終了のお知らせ 
goo

メニュー作成

モジュール mod_MakeMenu - 複数行文字列からメニューを作成
mod_MakeMenu.hsp
#ifndef MOD_MAKEMENU_HSP_
#define global MOD_MAKEMENU_HSP_

#include "user32.as"

#module mod_MakeMenu mhMenu, mFlag, mhWnd, mBeginID, mEndID, mLabel

#enum MMI_TAB = 0
#enum MMI_POSMENU
#enum MMI_POSSTR
#enum MMI_PARENT
#enum MMI_SUB
#enum MMI_MAX

#define MMF_MENU     0x0001
#define MMF_SETMENU  0x0002
#define MMF_POPMENU  0x0004

#defcfunc MakeMenuFromStr int hMenu, str strMenu, int beginID
	if ( hMenu == 0 || strMenu == "" ){ return 0 }
	buf = strMenu
	id = beginID
	split buf, "\n", spBuf
	len = length(spBuf)
	dim arItem, MMI_MAX, len
	repeat len
		cntTmp = cnt
		tmp = 0
		if ( peek(spBuf(cnt), 0) != '\t' ){
			if (peek(spBuf(cnt), 1) == '\t' ){
				tmp = 2
				arItem(MMI_TAB, cnt) = 1
				arItem(MMI_POSSTR, cnt) = 2
			}
		}
		if ( tmp == 0 ){
			arItem(MMI_TAB, cnt) = 0
			arItem(MMI_POSSTR, cnt) = 0
		}
		repeat -1, tmp
			if ( peek(spBuf(cntTmp), cnt) == '\t' ){
				arItem(MMI_TAB, cntTmp)++
				arItem(MMI_POSSTR, cntTmp)++
			}
			else { break }
		loop
	loop
	dim mi, 12
	mi(0) = 48
	repeat len
		cntTmp = cnt
		arItem(MMI_POSMENU, cnt) = 0 : arItem(MMI_PARENT, cnt) = hMenu
		if ( cnt ){
			tmp = cnt
			repeat
				tmp--
				if ( arItem(MMI_TAB, tmp) == arItem(MMI_TAB, cntTmp) ){ arItem(MMI_POSMENU, cntTmp)++ }
				else {
					if ( arItem(MMI_TAB, tmp) < arItem(MMI_TAB, cntTmp) ){
						arItem(MMI_PARENT, cntTmp) = arItem(MMI_SUB, tmp)
						break
					}
				}
				if ( tmp == 0 ){ break }
			loop
		}
		tmp = 0
		if ( cnt + 1 != len ){
			if ( arItem(MMI_TAB, cnt) < arItem(MMI_TAB, cnt + 1) ){ tmp = 1 }
		}
		if ( tmp ){
			mi(1) = 0x16
			CreatePopupMenu
			mi(5) = stat
			arItem(MMI_SUB, cnt) = mi(5)
		}
		else {
			mi(1) = 0x12
			tmp = strlen(spBuf(cnt)) - arItem(MMI_POSSTR, cnt)
			if ( tmp ){ mi(2) = 0 } else { mi(2) = 0x800 }
		}
		mi(4) = id
		id++
		mi(9) = varptr(spBuf(cnt)) + arItem(MMI_POSSTR, cnt)
		InsertMenuItem arItem(MMI_PARENT, cnt), arItem(MMI_POSMENU, cnt), 1, varptr(mi)
	loop
	dim buf, 1 : dim spBuf, 1 : dim arItem, 1
	return 1

#defcfunc MakeMenu str strMenu, int beginID
	CreateMenu
	menu = stat
	if ( MakeMenuFromStr(menu, strMenu, beginID) == 0 ){
		DestroyMenu menu
		return 0
	}
	return menu

#defcfunc MakePopMenu str strMenu, int beginID
	CreatePopupMenu
	menu = stat
	if ( MakeMenuFromStr(menu, strMenu, beginID) == 0 ){
		DestroyMenu menu
		return 0
	}
	return menu

#modcfunc MakeMenu_Make str strMenu, int beginID, int bPop
	if ( MakeMenu_Del(thismod) == 0 ){ return 0 }
	if ( bPop ){
		mhMenu = MakePopMenu(strMenu, beginID)
		if ( mhMenu ){ mFlag = MMF_POPMENU }
	}
	else {
		mhMenu = MakeMenu(strMenu, beginID)
		if ( mhMenu ){ mFlag = MMF_MENU}
	}
	if ( mhMenu ){
		mBeginID = beginID
		mEndID = id
	}
	return mhMenu

#modcfunc MakeMenu_Del
	if ( mhMenu == 0 ){ return 1 }
	if ( mFlag & MMF_MENU ){
		if ( mFlag & MMF_SETMENU ){
			SetMenu mhWnd, 0
			mhWnd = 0
		}
	}
	if ( mhMenu ){
		DestroyMenu mhMenu
		mhMenu = 0
	}
	mFlag = 0
	mhWnd = 0
	mBeginID = 0
	mEndID = 0
	mLabel = 0
	return stat

#modcfunc MakeMenu_Show int bShow
	if ( (mFlag & MMF_MENU) == 0 ){ return 0 }
	if ( bShow ){
		if ( mhMenu == 0 ){ return 0 }
		GetMenu hwnd : menu = stat
		if ( menu == 0 ){ menu = 1 }
		SetMenu hwnd, mhMenu
		if ( stat == 0 ){ return 0 }
		mhWnd = hwnd
		mFlag = MMF_MENU | MMF_SETMENU
	}
	else {
		if ( mhWnd == 0 ){ return 0 }
		else {
			GetMenu mhWnd : menu = stat
			if ( menu == 0 ){ return 1 }
		}
		SetMenu mhWnd, 0
		if ( stat == 0 ){ return 0 }
		mhWnd = 0
		mFlag = MMF_MENU
	}
	return menu

#modcfunc MakeMenu_PopEx int x, int y, int flag
	if ( mFlag != MMF_POPMENU ){ return 0 }
	TrackPopupMenu mhMenu, flag, x, y, 0, hWnd, 0
	return stat

#modcfunc MakeMenu_Pop
	GetCursorPos varptr(pt)
	return MakeMenu_PopEx(thismod, pt(0), pt(1), 0)

#modcfunc MakeMenu_SetLabel array menuLabel
	if ( mhMenu == 0 ){ return 0 }
	if ( vartype(menuLabel) != 1 ){ return 0 }
	len = mEndID - mBeginID
	tmp = length(menuLabel)
	if ( tmp < len ){ return 0 }
	dimtype mLabel, 1, tmp
	repeat tmp : mLabel(cnt) = menuLabel(cnt) : loop
	return 1

#modcfunc MakeMenu_CallLabel int wp
	if ( vartype(mLabel) != 1 ){ return 0 }
	tmp = wp >> 16
	if ( tmp != 0 ){ return 0 }
	tmp = wp & 0xffff
	if ( (mBeginID 
関数
関数名説明
hMenu = MakeMenu(strMenu, beginID)
メニューを作成します。
strMenu: メニュー作成用の文字列
beginID: 最初のメニューID
戻り値: 成功ならメニューハンドル、失敗なら0。
hMenu = MakePopMenu(strMenu, beginID)
ポップアップメニューを作成します。
strMenu: メニュー作成用の文字列
beginID: 最初のメニューID
戻り値: 成功ならメニューハンドル、失敗なら0。
モジュール関数名説明
モジュール型変数の作成
newmod mod, mod_MakeMenu, strMenu, beginID, bPop
mod: 作成されるmod_MakeMenuモジュール型変数
strMenu: メニュー作成用の文字列
beginID: 最初のメニューID
bPop: ポップアップメニューを作成する場合1、メニューを作成する場合0を指定。
ret = MakeMenu_Make(mod, strMenu, beginID, bPop)
メニューを再作成します。
strMenu: メニュー作成用の文字列
beginID: 最初のメニューID
bPop: ポップアップメニューを作成する場合1、メニューを作成する場合0を指定。
戻り値: 成功ならメニューハンドル、失敗なら0。
ret = MakeMenu_Del(mod)
メニューを破棄します。
戻り値が0なら失敗で、それ以外は成功です。
ret = MakeMenu_Show(mod, bShow)
メニューの表示、非表示を設定します。
bShow:
1の場合、現在アクティブなウィンドウにメニューを表示します。
0の場合、メニューを表示させたウィンドウのメニューを非表示にします。
戻り値が0なら失敗で、それ以外は成功です。
ret = MakeMenu_Pop(mod)
現在のマウス位置に、ポップアップメニューを表示します。
戻り値が0なら失敗で、それ以外は成功です。
ret = MakeMenu_PopEx(mod, x, y, flag)
任意の位置に、ポップアップメニューを表示します。
x: 水平位置を、スクリーン座標で指定します。
y: 垂直位置を、スクリーン座標で指定します。
flag: こちらを参照。TrackPopupMenu function
戻り値が0なら失敗で、それ以外は成功です。
ret = MakeMenu_SetLabel(mod, menuLabel)
モジュールにラベル配列を登録します。
menuLabel: メニューが押されたときに実行するラベル配列を指定。
戻り値が1なら成功で、0なら失敗です。
ret = MakeMenu_CallLabel(mod, wp)
wparamから該当するメニューのIDがあれば、ラベルをgosubします。
wp: wparam。
戻り値が1ならラベル実行。0なら該当IDではありません。
hMenu = MakeMenu_GetMenu(mod)
メニューハンドルを返します。
flag = MakeMenu_GetFlag(mod)
メニューの状態を返します。
0:作成されていません。
1:メニューが作成されています。
3:メニューが作成され、ウィンドウに表示されています。
4:ポップアップメニューが作成されています。
id = MakeMenu_GetBeginID(mod)
最初のメニューIDを返します。
size = MakeMenu_IDSize(mod)
メニューIDの数を返します。
name = MakeMenu_GetName(mod, nID)
指定したIDのメニューアイテム名を返します。
nID: メニューID
戻り値が""なら失敗で、それ以外は成功です。
ret = MakeMenu_SetName(mod, nID, str name)
指定したIDのメニューアイテム名を変更します。
nID: メニューID
name: 新しいメニューアイテム名
戻り値が0なら失敗で、それ以外は成功です。
ret = MakeMenu_Checked(mod, nID, int bCheck)
指定したIDのメニューアイテムのチェックを設定、取得します。
nID: メニューID
bCheck:
-1: チェック状態を取得します。戻り値は、0ならチェック無しで1ならチェック有です。
0: チェック無しの状態に設定します。戻り値が0なら失敗で、それ以外は成功です。
1: チェック有りの状態に設定します。戻り値が0なら失敗で、それ以外は成功です。
ret = MakeMenu_Disabled(mod, nID, bDisabled)
指定したIDのメニューアイテムの有効状態を設定、取得します。 無効状態の場合、押しても反応しません。
nID: メニューID
bCheck:
-1: 有効状態を取得します。戻り値は、0なら有効で1なら無効です。
0: 有効の状態に設定します。戻り値が0なら失敗で、それ以外は成功です。
1: 無効の状態に設定します。戻り値が0なら失敗で、それ以外は成功です。
ret = MakeMenu_SetID(mod, nID, newID)
指定したIDを変更します。
nID: メニューID
newID: 変更するID
戻り値が0なら失敗で、それ以外は成功です。
メニュー作成用文字列
メニュー用文字列は、複数行で構成され、各行はタブ(0以上)と文字列で構成されます。タブはメニューの階層を意味します。
また、行頭に任意の半角文字列1文字とタブ(1以上)の場合、最初の1文字は無視されます。
文字列を省略した場合セパレータが追加されます。
メニュー作成用文字列の例
#include "mod_MakeMenu.hsp"
	strMenu  = "ファイル(&F)\n"
	strMenu += "	開く(&O)\n"
	strMenu += "	\n"
	strMenu += "	終了(&X)\n"
	strMenu += "ヘルプ(&H)\n"
	strMenu += "	バージョン情報(&A)"
	newmod modMenu, mod_MakeMenu, strMenu, 0x8000, 0
	ret = MakeMenu_Show(modMenu, 1)
	stop
#include "mod_MakeMenu.hsp"
	strMenu =     {"ファイル(&F)
			|	開く(&O)
			|	
			|	終了(&X)
			ヘルプ(&H)
			|	バージョン情報(&A)"}
	newmod modMenu, mod_MakeMenu, strMenu, 0x8000, 0
	ret = MakeMenu_Show(modMenu, 1)
	stop
#include "mod_MakeMenu.hsp"
	strMenu = "ファイル(&F)\n\t開く(&O)\n\t\n\t終了(&X)\nヘルプ(&H)\n\tバージョン情報(&A)"
	newmod modMenu, mod_MakeMenu, strMenu, 0x8000, 0
	ret = MakeMenu_Show(modMenu, 1)
	stop
メニューIDについて
メニューIDは、指定したbeginIDから順番に付けられます。
上記の例でいえば、ファイル(0x8000),開く(0x8001), セパレータ(0x8002),終了(0x8003),ヘルプ(0x8004) バージョン情報(0x8005)となります。
メニューIDを指定する場合、0x8000から0xbfffを指定すること(0x0000から0x3ffffも可能)。 これはWM_COMMANDで以下の様に処理されている為か、ID & 0x4000のメニューアイテムが選択されるとエラー(#Error 3 in line 5 (???) -->パラメータの値が異常です)が出るので注意。ちなみに、CreateWindow等で作成されたコントロールに付けるIDについても同じです。
#define MESSAGE_HSPOBJ	0x4000

	case WM_COMMAND:
		if ( wParam & MESSAGE_HSPOBJ ) {
			// HSP内部処理
		}
		return 0;
WM_COMMAND 0x0111
メニューを押されたときの処理は、oncmdでWM_COMMANDを指定したそのジャンプ先で行うことができます。
wparamの上位ワード(wparam >> 16)が0の時がメニューのメッセージです。
wparamの下位ワード(wparam & 0xffff)がメニューIDです。
以下サンプル。
#include "mod_MakeMenu.hsp"

	screen 0, 300, 300
	strMenu =     {"ファイル(&F)
			|	開く(&O)
			|	
			|	終了(&X)
			ヘルプ(&H)
			|	バージョン情報(&A)"}
	newmod modMenu, mod_MakeMenu, strMenu, 0x8000, 0
	ret = MakeMenu_Show(modMenu, 1)
	mbBuf = ""
	mesbox mbBuf, ginfo(12), ginfo(13)
	oncmd gosub *WM_COMMAND, 0x0111
	stop
*WM_COMMAND
	hw = wparam >> 16
	lw = wparam & 0xffff
	if( hw == 0 ){
		if ( lw == 0x8001 ){
			dialog "txt", 16
			if ( stat == 0 ){ return }
			filename = refstr
			exist filename
			sdim mbBuf, strsize
			bload filename, mbBuf
			objprm 0, mbBuf
			return
		}
		if ( lw == 0x8003 ){
			end
		}
		if ( lw == 0x8005 ){
			dialog "mod_MakeMenu Ver 1.0"
			return
		}
	}
	// メニュー以外の処理
	return
MakeMenu_SetLabelとMakeMenu_CallLabel
特に便利なことはありませんが、ラベル配列を使うことで記述を少し減らすことができます。以下サンプル。
1. 最初に、各メニューIDを実行するラベルと、それを格納するラベル配列を用意します。
ラベル配列 = ファイル, 開く, セパレータ, 終了, ヘルプ, バージョン情報
ファイル、セパレータ、ヘルプは押されてもラベル実行はされませんが、何か適当なラベルを割り当てておきます。ラベル配列のサイズ(length)は、最低でもメニューアイテムの総数以上でなければ、エラーとなります。
2. MakeMenu_SetLabelで、上記ラベル配列を指定して呼び出します。
3. WM_COMMANDで、MakeMenu_CallLabelを呼び出します。
第一引数に、wparamを指定します。メッセージが登録されたIDの場合、該当ラベルを呼び出します。その時の戻り値は1で、呼び出されなければ0です。
#include "mod_MakeMenu.hsp"
	strMenu = "ファイル(&F)\n\t開く(&O)\n\t\n\t終了(&X)\nヘルプ(&H)\n\tバージョン情報(&A)"
	newmod modMenu, mod_MakeMenu, strMenu, 0x8000, 0
	menuLabel = *CMD_OPEN, *CMD_OPEN, *CMD_OPEN, *CMD_EXIT, *CMD_OPEN, *CMD_ABOUT
	ret = MakeMenu_SetLabel(modMenu, menuLabel)
	ret = MakeMenu_Show(modMenu, 1)
	mbBuf = ""
	mesbox mbBuf, ginfo(12), ginfo(13)
	oncmd gosub *WM_COMMAND, 0x0111
	stop
*CMD_OPEN
	dialog "txt", 16
	if ( stat == 0 ){ return }
	filename = refstr
	exist filename
	sdim mbBuf, strsize
	bload filename, mbBuf
	objprm 0, mbBuf
	return
*CMD_EXIT : end
*CMD_ABOUT : dialog "mod_MakeMenu Ver 1.0" : return
*WM_COMMAND
	if( MakeMenu_CallLabel(modMenu, wparam) ){ return }
	// メニュー以外の処理
	return
コメント ( 0 ) | Trackback ( 0 )

mod_ScreenResize

mod_ScreenResize
現在アクティブなウィンドウをサイズ変更可能にします。 リサイズ後のクライアントサイズは変わりません。
#include "mod_ScreenResize.hsp"
	screen 0, 300, 300
	ScreenResize
	stop
コメント ( 0 ) | Trackback ( 0 )

cnvstow

cnvstow
下記のcnvstowエラーは、2012/06/14 3.31β1 で、修正されています。

 cnvstowの第一引数に指定する変数は、(変換元の文字列サイズ + 1) * 2 以上確保する必要があります。 そうでない場合、予期しないエラーが発生する可能性があります。 コード1を実行、終了後にエラー報告ダイアログが出ました。 この件は、HSP3のバグトラックに報告しています。
コード1 - 終了時にエラーが発生する可能性があります
	sdim dst, 64
	sdim src, 1024
	repeat 1000 : src += "x" : loop
	cnvstow dst, src
	stop
 UNICODE変換は、hsp3ext_win.cppのcnvwstr関数を使用しているようですが、 cnvstowではwchar_t単位ではなくchar単位でbufsizeを指定しているためバッファオーバーフローしているようです。
int cnvwstr( void *out, char *in, int bufsize )
{
	//	sjis->unicode に変換
	//
	return MultiByteToWideChar( CP_ACP, 0, in, -1, (LPWSTR)out, bufsize );
}
dupptr
 HSP3掲示板 重複した範囲の dupptr についてより。
通常文字列変数とクローン文字列変数では、代入方法が違うようです。
hspvar_str.cppのHspVarStr_Set関数は、
static void HspVarStr_Set( PVal *pval, PDAT *pdat, const void *in )
{
	char **pp;
	if ( pval->mode == HSPVAR_MODE_CLONE ) {
		strncpy( (char *)pdat, (char *)in, pval->size );
		return;
	}
	pp = (char **)sbGetOption( (char *)pdat );
	sbStrCopy( pp, (char *)in );
	//strcpy( GetPtr(pval), (char *)in );
}
とあります。MSDNによればstrncpyは、
char *strncpy(char *strDest, const char *strSource, size_t count);
strncpy 関数は、strSource の最初の count の文字数を strDest にコピーし、strDest を返します。count で指定した文字数が strSource の文字数より少ない場合、NULL 文字はコピー先の文字列に追加されません。count で指定した文字数が strSource の文字数よりも多い場合は、count の文字数になるまで、コピー先文字列に NULL 文字が埋め込まれます。コピー元の文字列とコピー先の文字列が重なり合う場合、strncpy 関数の動作は未定義です。
とあります。大きなサイズや頻繁に代入が必要なクローン文字列変数を使う場合、代入は使わないでmemcpyなどを使用したほうがいいかと思います。 逆に、常にクリアしたい時は便利かもしれません(固定バッファサイズの文字列を送信する時など)。
コメント ( 0 ) | Trackback ( 0 )

cnvstowの修正

cnvstowの修正について。
下記、history.txtより引用
2012/06/14 3.31β1 cnvstow命令でバッファオーバーフローが発生することがある不具合を修正(BT#245)
コメント ( 0 ) | Trackback ( 0 )

ファイルハンドルからファイル名を取得

GetNameFromHandle
URLObtaining a File Name From a File Handle
GetNameFromHandle.hsp
#include "kernel32.as"
#uselib "psapi.dll"
#func global GetMappedFileName "GetMappedFileNameA" int, int, int, int

#module

#defcfunc GetFileNameFromHandle int hFile
	hMap = 0 : pMem = 0
	sdim szFileName, 260
	GetFileSize hFile, 0 : size = stat
	if ( size == -1 ){ return szFileName }

	CreateFileMapping hFile, 0, 0x02, 0, 1, 0 : hMap = stat
	if ( hMap ){
	  MapViewOfFile hMap, 0x04, 0, 0, 1 : pMem = stat
	  if ( pMem ){
	    GetCurrentProcess
	    GetMappedFileName stat, pMem, varptr(szFileName), 260
	    if ( stat ){
              sdim szTmp, 512
	      GetLogicalDriveStrings 511, varptr(szTmp)
	      if ( stat ){
	        driveLen = 0 : szDrive = " :" : sdim szName, 260
	        repeat
	          poke szDrive, 0, peek(szTmp, driveLen)
	          if ( szDrive == "" ){ break }
	          QueryDosDevice varptr(szDrive), varptr(szName), 260
	          if ( stat ){
	            if ( instr(szFileName, 0, szName ) == 0 ){
	              lstrlen varptr(szName)
	              nameLen = stat
	              if ( strmid(szFileName, nameLen, 1 ) == "\\" ){
	                getstr szName, szFileName, nameLen, '\0', 260
	                szFileName = szDrive + szName
	                break
	              }
	            }
	          }
	          lstrlen varptr(szTmp) + driveLen : driveLen += stat + 1
	        loop
	      }
            }
	    UnmapViewOfFile pMem
	  }
	  CloseHandle hMap
	}
	return szFileName

#global

	dialog "*", 16
	if ( stat == 0 ){ end }

	fileName = refstr
	CreateFile fileName, 0x80000000, 1, 0, 3 , 0, 0
	hFile = stat
	if ( hFile != -1 ){
		mes GetFileNameFromHandle(hFile)
		CloseHandle hFile
	} else { mes "error" }
コメント ( 0 ) | Trackback ( 0 )
« 前ページ 次ページ »