■HSP3の「仕様」のようなもの
HSPをありがたく使わせていただいてます。
HSP3の「仕様」のようなものを思いつくままにまとめてみました。
●プログラムループと割り込み
■プログラムループ
プログラムループはデスクトップや他のアプリケーションのウィンドウが前面表示されているばあいも実行されます。
デスクトップや他のアプリケーションのウィンドウが前面表示されているときに、プログラムループが実行されないようにするには、システム変数ginfo_actで判定してプログラムループの先頭に戻ればよいでしょう。
■割り込み
HSPの割り込みは、wait、await、stop命令で停止しているときに受けつけますので、割り込みサブルーチン中のwaitで割り込み入力を受けつけることのないように注意したほうがよいでしょう。
waitやawaitで割り込みを受けると、その時点でwait値は無視され、割り込み後の戻り先はwaitやawaitの次のコマンドになります。
割り込み処理の優先順序は、oncmd命令 → onclick命令やonkey命令 の順になっているようです。
button命令も割り込みのひとつで、wait,await,stop命令で停止しているときにボタンのクリックを受けつけます。以下の例で、button gosubの戻り先がwaitの次の行になることがわかります。
ところで、HSPのオブジェクトは少しクセがあるようです。以下のような例では、ボタン操作が正しくおこなわれません。button以外の他のオブジェクトでも同じようになります。
上の例を改善すると、以下のようになり、ボタン操作が正しくおこなわれます。
onclick命令とonkey命令による割り込みは操作先ウィンドウにかかわらず認識されます(プログラムループではありませんので、デスクトップや他のアプリケーションのウィンドウが前面表示されているばあいは認識されません)。onclick 0 または onclick 1 および onkey 0 または onkey 1 による割り込みの一時停止、再開もすべてのウィンドウに反映されます。
オブジェクトを配置してみましょう。下例では、onkey割り込みはinput、mesbox、listbox、combox、button、chkboxがフォーカスされているときでも割り込みを受けつけますが、onclick割り込みはinput、mesbox、listbox、combox、button、chkboxをマウスクリックしても受けつけられません。
oncmd命令による割り込みは、命令が実行された操作先ウィンドウのみで認識されます(ginfo_intidに割り込みの発生したウィンドウIDが格納されます)。複数のウィンドウを作成している場合は、 ウィンドウごとにoncmd命令による登録が可能です。ところが、oncmd 0 および oncmd 1 による割り込みの一時停止、再開はすべてのウィンドウに反映されます。
オブジェクトを配置してみましょう。下記の例では、input、mesbox、listboxをマウスクリックしても割り込みは受けつけられません。また、マウスホイールの操作はinput(他にbutton,chkbox,comboxなど)がフォーカスされているときは受けつけられますが、mesboxまたはlistbox(他にlistviewなど)がフォーカスされているときは受けつけられません。
マウスホイール操作の割り込みを常に受けつけるようにするためには、すべてのオブジェクトがフォーカスされないようにすればよいでしょう。また、たとえばsbcobj.hpiプラグインをつかって、mesbox、listbox(他にlistviewなど)がフォーカスされているときにもマウスホイール操作の割り込みを受けつけるようにするのもよいでしょう。sbcobj.hpiについてはネットで検索してください。
以下は、oncmd割り込みの許可、禁止の例です。
oncmdでWM_NOTIFYメッセージを取得する割り込み処理プログラムでonkey 0の割込制御を使用すると、button/chkboxオブジェクトがフォーカス中にonkey割り込みによる[↓][↑]入力の取得ができなくなります。以下の例では、listviewオブジェクトがフォーカスされないようになっています。すべてのオブジェクトがフォーカスされないようにするのもよいでしょう。
割り込みは (a)wait 命令(またはstop命令)の実行中に発生します。また、(a)wait 命令では描画の更新もおこなわれます。割込処理後ただちに描画を更新したいという要求をみたすためには、以下のような工夫をすればよいでしょう。
(A)割込プログラムで実際の処理をし、フラグ(下図:FlgA)をセットする。メインプログラムでは、そのフラグを判定してプログラムループに戻る。
(B)割込プログラムでフラグ(下図:FlgB)をセットする。メインプログラムでは、そのフラグを判定して実際の処理をしたのちプログラムループに戻る。
プログラムの流れ [メインプログラム]
+------------+
*1 このwaitで割込が発生する。 |プラグイン |
*2 割込処理中は割込禁止とする。 |モジュール |
ただしWM_NOTIFYメッセージの取得では |マクロ定義 |
onkey 0の割込制御は使えない。 +------------+
*3 *1のwaitの直後で割込禁止とする。 |設定その他 | onexit/onkey/onclick命令で
プログラムループおよびサブルーチンで新たな | | 割り込みを定義する
割込が発生しないように。 +------------+
*4 *1のwaitの直前で割込許可とする。 |画面作成 | oncmd命令やbutton命令で
| | 割り込みを定義する
(注意) +------------+
WM_NOTIFYメッセージの取得ではは、*2と*3 |プログラムループ |
のoncmdの割込制御は使えない。 |*pl |<--+
*4のoncmdの割込制御も無意味になる。 | onkey 1 *4| |
(各種操作) | onclick 1 | |
[割込プログラム] 割り込み発生 |(oncmd 1) | |
+------------+<---------------------+ wait 1 *1| |
|(onkey 0) *2+--waitの次行に戻る--->| onkey 0 *3| |
| onclick 0 | | onclick 0 | |
|(oncmd 0) | |(oncmd 0) | |
| | +----------+ | | |
| 割込A +---->|サブルーチン | | | |
| FlgAセット |<----+実際の処理| | (FlgA判定) | |
| | +----------+ | goto *pl+---+ 描画更新が必要なときは
| | | | | 必ずプログラムループに戻ること
| 割込B | +----------+ | | |
| FlgBセット | |サブルーチン |<----+ (FlgB判定) | |
| | |実際の処理+---->| -> goto *pl+---+
| | +----------+ | | |
+------------+ | | |
| | |
+----------+ | | |
|サブルーチン |<----+割込外の条件| |
|実際の処理+---->| -> goto *pl+---+
+----------+ | | |
| | |
| goto *pl+---+
+------------+
■割り込みプログラム例
マウスドラッグによるウィンドウ移動も割り込みを使えば簡単にできます。
ドロップファイルの情報の取得も割り込みを使えば簡単にできます。
●ウィンドウ
■アクティブウィンドウと操作対象ウィンドウ
HSPではウィンドウを作成した時点で、そのウィンドウがアクティブウィンドウであり、操作対象ウィンドウでもあります。アクティブウィンドウが変更になっても、操作対象ウィンドウが変更されるわけではありません。操作対象ウィンドウはプログラムの gsel 命令で指定します。
■ダブルクリック
screen命令で作成したウィンドウはダブルクリックを受けつけません。
・ウインドウクラスのスタイルをダブルクリックを受けつけるように書き換えます。
・ダブルクリックのウィンドウ通知メッセージを取得します。
・ダブルクリックとシングルクリックの判定にはタイマを利用します。
■dialog
HSPのdialog はカレントスクリーン(gsel操作対象)をアクティブにします。
操作先ウィンドウが非表示だと、dialog は画面の下に回り込んでしまいます。
■子画面化
親画面の外に出ることができる子画面と、出ることができない子画面があります。
親画面の外に出ることができる子画面のばあい、親画面を操作禁止状態にしても子画面の操作は許可されます。
親画面の外に出ることができない子画面のばあい、親画面を操作禁止状態にすると子画面の操作も禁止されます(このばあい、子画面だけを操作許可/禁止することはできませんし、プログラムから子画面の操作許可/禁止状態を知る方法もないようです)。
子画面をマウスクリックしても親画面のウィンドウタイトルがサチらないようにするには以下のようにします。
【ウィンドウスタイル】
サイズ可変のscreenのウィンドウスタイル (screen0以外で第4パラメータ+4を除く)
16ce0000=| WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_CAPTION | WS_THICKFRAME | WS_SYSMENU | WS_MINIMIZEBOX
WS_THICKFRAMEが含まれる
WS_CLIPCHILDRENを含む、WS_CHILDを含まない
第4パラメータ+8はGWL_STYLEではなくGWL_EXSTYLE のWS_EX_TOOLWINDOW
第4パラメータ+8+4でWS_THICKFRAMEが含まれる場合はタイトルバーの下のバックが透ける
サイズ固定のscreenのウィンドウスタイル (screen0 および sscreen0以外で第4パラメータ+4の場合)
16ca0000=| WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX
WS_THICKFRAMEが含まれない
WS_CLIPCHILDRENを含む、WS_CHILDを含まない
第4パラメータ+8はGWL_STYLEではなくGWL_EXSTYLE のWS_EX_TOOLWINDOW
bgscrのウィンドウスタイル
0x96000000=| WS_VISIBLE | WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS
 WS_CLIPCHILDRENを含む、WS_CHILDを含まない
|
|
ウィンドウの表示、非表示を操作するとき、次に表示されるウィンドウが既知であるとは限りません。ひとつのウィンドウを非表示にしたとき、次に前面化されるウィンドウがどれかは不定です。次の例では、スペースキーの入力で最前面の画面を探して非表示にしています。親画面をマウスクリックするなどして子画面からフォーカスが失われてしまったばあいにも、一番手前にある子画面を見つけだすことができます。
●オブジェクト
■オブジェクトID
オブジェクトを作成しても入力フォーカスは変化しません(オブジェクトIDのデフォルトは0)。
dialogで入力フォーカスは失われます(オブジェクトIDは-1になる)。
■mesbox
mesbox,input,listbox・・・の変数は再初期化してはいけません。
変数を再初期化するとポインタが変化して、objprm命令などを実行したとき変数を見失いエラーになります。
どうしても変数の内容をクリアする必要がある場合は、最初に
sdim txt_buf, $ffff
のように変数を初期化しておき、以降は、
memset txt_buf, 0, $ffff
のようにしなければなりません。
mesbox の内容をobjprm命令で書き換えたとき、変数は正しく更新されません(input の変数はなぜかしらobjprm命令で更新されます)。
変数を正しく更新したいときは、mesbox に対してEM_REPLACESELとEM_REPLACESELをメッセージ送信します(ふつうは変数を代入してからmesbox の内容をobjprm命令で書き換えるようです)。
mesbox の32767バイト以上の変数の長さがstrlen()では誤認します。
変数の長さを正しく判定するためには、mesbox に対してWM_GETTEXTLENGTHをメッセージ送信します。
■listview
llmod3のlistview.hspはとても便利ですが、欄の高さを調整することができません。
そこで、アイコンをセットするふりをして欄の高さを調整するという裏技の出番です。
リストビューのフォント(WM_SETFONT)、リスト背景色(LVM_SETBKCOLOR)、文字背景色(LVM_SETTEXTBKCOLOR)、文字色(LVM_SETTEXTCOLOR)はメッセージ送信(SendMessage)で指定することができます。
リストビューの行ごとに背景色と文字色を指定するには、WM_NOTIFY通知メッセージ(NMHDR構造体:NM_CUSTOMDRAW)でカスタムドローの描画状態(NMLVCUSTOMDRAW構造体)を取得、設定します。
リストビューのマウスクリックは、WM_NOTIFY通知メッセージ (NMHDR構造体:NM_CLICK、NM_DBLCLK、NM_RCLICK、NM_RDBLCLK)で取得できます。ダブルクリックとシングルクリックの判定は、タイマを利用します(既述)。
リストビューの選択アイテム(選択行)は、WM_NOTIFY通知メッセージ (NMHDR構造体:LVN_ITEMCHANGED)で取得できます。
リストビューはデータ量が多くなると表示が遅くなります。
そういう場合は、アイテムだけ書き込んでおいて、サブアイテム(欄)は表示されている分だけ書き込めばよいでしょう。メッセージ送信(SendMessage)で表示先頭行(LVM_GETTOPINDEX)を取得し、listmax命令(第2パラメータは1)で表示行数を得ます。
リストビューのちらつきの問題は解決の決め手はないようです。罫線のちらつきは、リストビューのスタイルに罫線を使わないようにして、カスタムドローで行ごとに背景色を指定すれば解決できますが、描画のちらつきまでは解消できません。カスタムドローで行ごとに背景色や文字色を変更する場合は、スクロールバーの操作でもちらつきが出るようです。
リストビューの操作許可/禁止は次のようになります。操作を禁止するとスクロールもできなくなってしまいます。
選択ができない表示だけのリストビューが欲しいときがあります。もちろん、スクロールはできなくてはなりませんから、上記の操作許可/禁止はつかえません。ポイントはリストビューのスタイルには'8'を指定しないようにし、他のオブジェクトを選択することにより目的が達せられます。スタイルの'8'は「listviewが選択されていないときでも、選択されているアイテムの色を変える」という意味です。手の形のマウスはリストビューのスタイル指定で普通の状態にできます。
なお、以下の例では、他のオブジェクトを配置しても正常に動作しないという問題(割り込みの例で既出)があります。
上記の選択ができない表示だけのリストビューに、自力で選択行の表示を付け加えると、次のようになります。ここまでくれば、条件により自在にアイテムの色(文字色・背景色)を変えることができるでしょう。
上記のリストビューに、[↑][↓][PgUp][PgDn]キーおよびマウスホイールでのリストのスクロールと、マウスクリック(左クリック、ダブルクリック、右クリック)および[Enter][スペース]キーでのアイテム選択の判別機能を追加すると、既出のリストビューのサンプルのようになります。
■tooltip
llmod3のmisc.hspのツールチップはウィンドウIDごとにひとつのtooltip(HSPのオブジェクト)を作成するようです。
llmod3のmisc.hspのツールチップは、複数のウィンドウを作成するとエラーになります。
handle_of_tt配列への代入でエラーが発生するのを回避するには、
#module命令の直前にdim handle_of_tt, 2048を追加し、
handle_of_tt(a)をhandle_of_tt@(a)に書き換えればよいでしょう。
llmod3のmisc.hspのツールチップの背景色は、ウィンドウIDごとに最後に実行したtooltip命令の第3パラメータのBkColor(ツールチップの背景色)が有効になります。
バルーン表示は、GetWindowLong/SetWindowLongでツールチップのウィンドウスタイルにTTS_BALLOONを追加すればよいのですが、llmod3のmisc.hspではTOOLINFO構造体のuFlagsのTTF_CENTERTIPがコメントアウトされていますので、このままでは表示位置がズレてしまいます。misc.hspの;|TTF_CENTERTIP の";"を削除することが必要です。
ツールチップに不満がある場合は、HtmlHelpのポップアップヘルプ(HSPのオブジェクトではありません)を検討してみてはどうでしょうか。
API補足説明
#uselib "hhctrl.ocx"
#func HtmlHelp "HtmlHelpA" sptr,sptr,sptr,sptr
; HWND hwndCaller, HTMLヘルプを呼び出すウィンドウのハンドル
; LPCSTR pszFile, HTMLファイルの名前 (呼び出し側のプログラムと異なるディレクトリに有る場合はパス名も付ける)
; 指定したコマンドがファイル名を必要としない場合も
; UINT uCommand, コマンドの1つを指定
; DWORD dwData dwDataは、uCommandの種類により意味が異なる
#const HH_INITIALIZE $001C
; dwDataにはDWORD型変数のポインタを指定(dwCookie)
#const HH_UNINITIALIZE $001D
; dwDataにはHH_INITIALIZEで指定したDWORD型変数のポインタを指定(dwCookie)
#const HH_DISPLAY_TEXT_POPUP $000E
; dwDataにはHH_POPUP構造体(配列のポインタ)を指定
; (0) int cbStruct 4*13
; (1) HINSTANCE hinst リソースを含むプログラムまたは、dllのインスタンスハンドルを指定 (idStringが0の時またはファイル名を表すときは無視される)
; (2) HUINT idString 0またはリソースIDまたはテキストファイルのトピックID
; (3) HLPCTStr pszText idStringが0の時表示するテキストを指定
; (4) HPOINT pt 表示するポップアップウィンドウの上辺の中心をどこに持っていくかを指定します。
; (5) ↓
; (6) HCOLORREF clrForeground ポップアップウィンドウのフォアグラウンドカラーのRGB値を指定 (-1でシステムカラー)
; (7) HCOLORREF clrBackground 背景色のRGB値を指定 (-1でシステムカラー)
; (8) HRECT rcMargins 上下・左右のマージン値を指定 (-1でデフォルト)
; (9) ↓
; (10) ↓
; (11) ↓
; (12) HLPCTStr pszFont フォントを指定します。
●命令/関数
■exist
exist命令はファイルが存在しない場合だけではなく、ファイルが他のプログラムで使用中の場合も strsizeに -1 を返します。
またファイルだけではなく、フォルダ、ドライブが使用可能かどうか調べることもできます。
・上記の方法でドライブが使用可能かどうか調べるとWindowsのエラーが表示されることがあります。「COM for HSP3」の■ディスクの情報を参照してください。
●ファイル
■ファイルのオープン制御
以下は、ファイルのオープン制御の例です。
実行すると、デスクトップの"新しいテキスト ドキュメント.txt"をさがし、オープンしたままの状態にします(他のアプリケーションから開くことができなくなります)。ちなみに、dirlist命令はオープン中(アプリケーションで使用中)のファイルもリストアップします。
●64bit版Windows
■64bit版Windows かどうか
32bit版Windows か 64bit版Windows かを調べるには以下のようにします。
■ファイル システム リダイレクタ
アプリケーションからWindowsが用意したEXE・DLL等を読みに行くアクセス先はWindowsのファイル システム リダイレクタという仕組みにより制御されていて、64bitアプリケーションであればC:\Windows\System32、32bitアプリケーションであればC:\Windows\SysWOW64になります。 これは、Windowsが用意したEXE・DLL等は32bitと64bitで同一の名前になっているので、アプリケーションが32bitか64bitかでアクセス先を変える必要があるからです。
どうしても、32bitアプリケーションからネイティブのシステム ディレクトリ(C:\Windows\System32)にアクセスする必要があるばあいは、Sysnativeエイリアスを使用して、ファイル システム リダイレクタを無効にします。 Sysnativeエイリアスは32bitアプリケーション用のものであり、64bitアプリケーションからは使用できないことに注意してください。