全然更新しないブログ
HSPメモ帳
COMオブジェクト
COMオブジェクト型変数作成命令
axobjとnewcomは、COMオブジェクトを作成します。querycomとcomeventは、既に存在するCOMオブジェクト型変数からオブジェクト型変数を作成します。
命令 | 概要 |
---|---|
axobj | ActiveXコントロールを作成 |
newcom | COMオブジェクトを作成 |
querycom | インターフェイスを取得 |
comevent | イベント用のインターフェイスを取得 |
newcom 作成モード:-1 | 外部関数などから得たインターフェイスポインタからオブジェクト型変数を作成 |
COM系命令の引数の種類
表2は、各命令で使用できる引数の種類について。oは命令が成功、xは失敗した時。
progidについては、
URLprogid - MSDN を参照。
CLSIDは、オブジェクトを作成する時、IIDはインターフェイスを取得する時に使用。CLSIDとIIDは、GUIDでありHSPでは文字列として扱う。また、ole32.dllのProgIDFromCLSIDやCLSIDFromProgIDで、ProgIDとCLSIDは変換可能。
GUIDについては、
URLGUID - Wikipedia を参照。
#usecomは、IIDとCLSIDまたはIIDからインターフェイス名の定義を行う。
ProgID記述例
ProgID = "Shell.Explorer.2"
guid文字列記述例
guid = "{00000000-0000-0000-C000-000000000046}"
#usecom定義例 - HSP HELPより引用
#define CLSID_ShellLink "{00021401-0000-0000-C000-000000000046}" #define IID_IShellLinkA "{000214EE-0000-0000-C000-000000000046}" #usecom IShellLinkA IID_IShellLinkA CLSID_ShellLink
ProgID | CLSID 文字列 | IID 文字列 | #usecom IIDとCLSID | #usecom IID | |
---|---|---|---|---|---|
axobj | o | o | x *1 | o | x *4 |
newcom | o | o | x *2 | o | x *4 |
querycom | x *5 | x *3 | o | o | o |
comevent | x *5 | x *6 | o | x *7 | x *7 |
newcom (-1) | o | o | o | o | x *4 |
*1 stat:-1
*2 stat:1
*3 stat:0
*4 #Error 30 無効な名前がパラメーターに指定されています
*5 #Error 3 パラメータの値が異常です
*6 #Error 39 外部オブジェクトの呼び出しに失敗しました
*7 #Error 32 関数のパラメーター記述が不正です
?newcom(-1)の*4について。作成モード-1でも、newcomの仕様なのかクラスを登録しないとエラーとなる。とりあえず適当なクラスを指定する場合は、"{}"を指定する。以下参照(4行)。空文字列("")を指定した場合はエラー(30)となる。
無名クラス指定
#include "ole32.as" #include "shell32.as" #define IID_IShellFolder "{000214E6-0000-0000-C000-000000000046}" #usecom IShellFolder IID_IShellFolder "{}" #comfunc ISF_ParseDisplayName 3 int,int,wstr,int,var,int shf = 0 SHGetDesktopFolder varptr(shf) if ( stat == 0 ){ newcom shell, IShellFolder, -1, shf dispName = dirinfo(0x10000) ISF_ParseDisplayName shell, 0, 0, dispName, 0, item, 0 if ( stat == 0 ){ mes "S_OK" CoTaskMemFree item } } stop
COMオブジェクトの破棄
COMオブジェクト型変数の破棄は、delcom命令を使用します。
delcom - HSP HELPより引用 |
---|
delcom命令は、初期化されたCOMオブジェクトの参照カウントを減らし、変数に設定されているインスタンスを無効にします。 通常、生成されたCOMオブジェクトのインスタンスはHSP内部で自動的に破棄されるため、特にdelcom命令で明示的に破棄する必要はありません。 一度破棄されたCOMオブジェクト型の変数は、再度newcom命令により初期化されるまでは使用することができません。 |
COMオブジェクトと参照カウント
code1.hspを実行すると、代入時には参照カウントが増え、delcomで減ることがわかります。
最初のxml1の参照カウントが3になっているのは、おそらく内部でカウントが+2された後にXML_Releaseが呼び出された結果であり、その後-2されているはずなので実際のカウントは1。よって正しい参照カウントは結果から-2したものとなります。また、代入以外でもquerycomやnewcom(3番目の引数に-2を指定)した時もカウント+1されます。
code1.hsp
#define global CLSID_XMLDOMDocument "{F6D90F11-9C73-11D3-B32E-00C04F990BB4}" #define global IID_IXMLDOMDocument "{2933BF81-7B36-11D2-B20E-00C04F983E60}" #usecom global XMLDOMDocument IID_IXMLDOMDocument CLSID_XMLDOMDocument #comfunc global XML_QueryInterface 0 int,int #comfunc global XML_AddRef 1 #comfunc global XML_Release 2 #module #defcfunc GetRef var v XML_AddRef v XML_Release v return stat #global newcom xml1, XMLDOMDocument mes "newcom xml1, XMLDOMDocument" mes "// xml1の参照カウント:" + GetRef(xml1) xml2 = xml1 mes "xml2 = xml1" mes "// xml1の参照カウント:" + GetRef(xml1) mes "// xml2の参照カウント:" + GetRef(xml2) delcom xml2 mes "delcom xml2" mes "// xml1の参照カウント:" + GetRef(xml1) stop
code1.hspの実行結果 |
---|
newcom xml1, XMLDOMDocument // xml1の参照カウント:3 xml2 = xml1 // xml1の参照カウント:4 // xml2の参照カウント:4 delcom xml2 // xml1の参照カウント:3 |
COMオブジェクトと配列
COMオブジェクト型変数を配列へ「=」を使った代入はできない。命令の引数に配列を指定することで代入は可能。しかし、配列要素の自動確保は行われない。下記、テストコード。エラーが出るので注意。
code2.hspは、初期化していないxml2を配列変数として代入しています。実行結果は「#Error 7 配列の要素が無効です」となります。
code3.hspは、dimtypeでxml3をCOMオブジェクト型変数(タイプ6)を要素4個の配列として初期化した後に、代入しています。実行結果は「#Error 39 外部オブジェクトの呼び出しに失敗しました」となります。
code4.hspは、dimtypeで配列を確保した後newcom命令で作成しています。1回目のnewcomは成功します。2回目のnewcomは、確保した以上の要素数を指定していますが自動確保されないのでエラーが発生します。エラー内容は、「#Error 7 配列の要素が無効です」。
COMオブジェクト型変数をモジュール変数として配列を扱う方法。
code5.hspは、エラーを出すことなく自動拡張を可能とした配列の例。
?しかし、(2)のように一度モジュール変数にCOMオブジェクト型変数を代入した後に、その変数を別の変数に代入しようとすると「#Error 1 システムエラーが発生しました」となるので注意。
code2.hsp
newcom xml1, "Microsoft.XMLDOM" xml2(0) = xml1
code3.hsp
newcom xml1, "Microsoft.XMLDOM" dimtype xml3, 6, 4 xml3(0) = xml1
code4.hsp
dimtype xml4, 6, 4 newcom xml4(0), "Microsoft.XMLDOM" newcom xml4(4), "Microsoft.XMLDOM"
COMオブジェクト型変数をモジュール変数として配列を扱う方法。
code5.hspは、エラーを出すことなく自動拡張を可能とした配列の例。
?しかし、(2)のように一度モジュール変数にCOMオブジェクト型変数を代入した後に、その変数を別の変数に代入しようとすると「#Error 1 システムエラーが発生しました」となるので注意。
code5.hsp
#module mod_XML mXML #modinit var v, int c mXML = v // (1) // tmp = mXML // (2) mXML->"LoadXML" "<cnt>" + c + "</cnt>" return #modfunc XMLPrint mes mXML("xml") return #global repeat 4 newcom xmlTmp, "Microsoft.XMLDOM" newmod modXML, mod_XML, xmlTmp, cnt loop xmlTmp = 0 repeat 4 XMLPrint modXML(cnt) loop stop
コメント ( 0 ) | Trackback ( 0 )
再利用2
HSP Ver3.3
#module
モジュール型変数の作成
モジュールの作成、使用は、開発の効率化に役立ちます。コード5,6は、モジュール型を使用した例です。モジュール型の変数を作成するためには、#moduleによる定義が必要です。#moduleの後ろにモジュール名を書きます(コード6のmod_Rect)。その後ろに、モジュール変数を書きます(コード6のmRect)。複数の場合は、「,」で区切ります。省略はできず、必ず一つ以上の変数名を書かなければいけません。また、モジュール変数は、#deffuncや#defcfuncからアクセスできません。#modinitは、newmodによりモジュール変数が作成された時に実行されます。#modtermは、delmodでモジュールが破棄されるか、プログラムが終了するときに実行されます。thismodは、モジュール関数内で、自分自身の関数を呼び出すときに使います。
コード5 - main.hsp
#include "mod_Rect.hsp" screen 0, 300, 300 newmod rc, mod_Rect MRect_SetRect rc, 100, 100, 100, 100 boxf 100, 100, 200, 200 repeat MRect_PtIn rc, mousex, mousey if ( stat ){ title "ON" } else { title "OFF" } wait 10 loop
コード6 - mod_Rect.hsp
#ifndef MOD_RECT_HSP_ #define MOD_RECT_HSP_ #include "user32.as" #module mod_Rect mRect #modfunc MRect_GetPtr return varptr(mRect) #modfunc MRect_GetRect array dst CopyRect varptr(dst), varptr(mRect) return stat #modfunc MRect_GetPos array dst dst(0) = mRect(0), mRect(1) return 1 #modfunc MRect_GetSize array dst dst(0) = mRect(2) - mRect(0) dst(1) = mRect(3) - mRect(1) return 1 #modfunc MRect_SetRect int x, int y, int w, int h SetRect varptr(mRect), x, y, x + w, y + h return stat #modfunc MRect_SetPos int x, int y mRect(0) = x, y return 1 #modfunc MRect_SetSize int w, int h mRect(2) = mRect(0) + w mRect(3) = mRect(1) + h return 1 #modfunc MRect_Copy var modRect MRect_GetPtr modRect CopyRect varptr(mRect), stat return stat #modfunc MRect_Equal var modRect MRect_GetPtr modRect EqualRect varptr(mRect), stat return stat #modfunc MRect_Inflate int x, int y InflateRect varptr(mRect), x, y return stat #modfunc MRect_Intersect var rcDst, var modRect MRect_GetPtr modRect IntersectRect varptr(rcDst), varptr(mRect), stat return stat #modfunc MRect_Offset int x, int y OffsetRect varptr(mRect), x, y return stat #modfunc MRect_PtIn int x, int y PtInRect varptr(mRect), x, y return stat #modfunc MRect_Init dim mRect, 4 return 1 #modfunc MRect_Term return 1 #modinit MRect_Init thismod return stat #modterm MRect_Term thismod return stat #global #endif
モジュールの再利用
コード8は、コード6のモジュールmod_Rectを編集せずに機能を追加しています。まず、モジュールmod_Drawのモジュール変数の最初に、モジュールmod_Rectのモジュール変数を書きます(コード8のmRect)。変数名を変えても問題ありませんが、mod_Rectの仕様に合わせる必要があります。そして、その後ろに、mod_Drawで使う変数を書きます(コード8のmhdc, mPos)。mod_Rectのmodinitとmodtermは、あえてモジュール関数を別に使用しています(コード6のMRect_Init, MRect_Term)。それを、mod_Drawでも利用します(コード8のMDraw_Init, MDraw_Term)。mod_Drawは、mod_Rectのモジュール関数を全て利用することができますが、mod_Rectは、mod_Rectにないモジュール変数を使ったmodDrawの関数は利用できません。
コード7 - main.hsp
#include "mod_Draw.hsp" gsel 0, -1 : wait 100 dim rc, 4 GetDesktopWindow : hWndT = stat GetWindowRect hWndT, varptr(rc) rc(2) -= rc(0) : rc(3) -= rc(1) buffer 1, rc(2), rc(3) : hdc1 = hdc GetDC hWndT : hdcT = stat BitBlt hdc, 0, 0, rc(2), rc(3), hdcT, 0, 0, 0xcc0020 ReleaseDC hWndT, hdcT screen 0, 400, 300 newmod draw, mod_Draw MDraw_Set draw, hdc1, 0, 0, rc(2), rc(3), 0, 0 MDraw_Draw2 draw , 0, 0, 400, 300 redraw 1 stop
コード8 - mod_Draw.hsp
#ifndef MOD_DRAW_HSP_ #define MOD_DRAW_HSP_ #include "gdi32.as" #include "mod_Rect.hsp" #module mod_Draw mRect, mhdc, mPos #define MDRAW_SET_ ¥ int hdc_, int x, int y, int w, int h, ¥ int px, int py #modfunc MDraw_Set MDRAW_SET_ mhdc = hdc_ mPos = px, py MRect_SetRect thismod, x, y, w, h return 1 #modfunc MDraw_Draw int x, int y #define BITBLT_ ¥ hdc, x, y, mRect(2) - mRect(0), ¥ mRect(3) - mRect(1), mhdc, mPos(0), mPos(1), 0xcc0020 BitBlt BITBLT_ return #modfunc MDraw_Draw2 int x, int y, int w, int h if ( mhdc == 0 ){ return 0 } #define STRETCHBLT_ ¥ hdc, x, y, w, h, ¥ mhdc, mPos(0), mPos(1), mRect(2) - mRect(0), ¥ mRect(3) - mRect(1), 0xcc0020 StretchBlt STRETCHBLT_ return stat #modfunc MDraw_Init MRect_Init thismod mhdc = 0 dim mpos, 2 return stat #modfunc MDraw_Term MRect_Term thismod return stat #modinit MDraw_Init thismod return stat #modterm MDraw_Term thismod return stat #global #endif
AXファイルサイズ
関数は、#deffuncで引数なしreturnのみ、モジュール関数も、#modfuncで引数なしreturnのみ。
項目\module数 | 0 | 1 | 2 | 5 | 10 |
モジュール変数:0 モジュール関数:0 関数:0 | 114 | 130 | 146 | 194 | 274 |
モジュール変数:0 モジュール関数:0 関数:3 | 114 | 267 | 420 | 885 | 1,665 |
モジュール変数:1 モジュール関数:3 関数:0 | 114 | 365 | 616 | 1,375 | 2,646 |
モジュール変数:3 モジュール関数:3 関数:3 | 114 | 510 | 906 | 2,106 | 4,117 |
モジュール内での定義
既に、globalで定義されている時に、モジュール内で重複定義(global無し)した場合、エラーもでず定義もされないので注意。globalを付けて定義した場合は、エラーがでます(コード9)。
コード9 - main.hsp
#define DEF_ "DEF_" #define global DEF_GLOBAL "DEF_GLOBAL" #module #define DEF_ "DEF_MOD_" // OK //#define global DEF_ "DEF_MOD_" // エラー #define DEF_GLOBAL "DEF_MOD_GLOBAL" // 無視 //#define global DEF_GLOBAL "DEF_MOD_GLOBAL" // エラー #deffunc Func1 mes DEF_ mes DEF_GLOBAL return #global Func1 stop
実行結果 - コード9
DEF_MOD_ DEF_GLOBAL
コメント ( 0 ) | Trackback ( 0 )
再利用1
HSP Ver3.3
#include
#includeで、指定ファイルのコードを挿入できます。ファイル内容は、「#define等を使った定義」、「#deffunc等を使った関数」、「モジュール定義」、「DLLの定義」、「COMの定義」等の組み合わせが考えられます。
関数
例えば、コード1,2のようにグローバル空間に記述するコードをインクルードすることは、再利用という点で考えると良くありません。コード1 - main.hsp
#include "sub1.hsp" // サイズ変更可能ウィンドウの作成 stop
コード2 - sub1.hsp
#uselib "user32.dll" #func GetWindowLong "GetWindowLongA" int,int #func SetWindowLong "SetWindowLongA" int,int,int #func SetWindowPos "SetWindowPos" int,int,int,int,int,int,int screen 0, ginfo_dispx , ginfo_dispy, 0, -1, -1, 300, 300 title "Sample" GetWindowLong hwnd, -16 SetWindowLong hwnd, -16 , stat | 0x50000 SetWindowPos hwnd, 0, 0, 0, 0, 0, 0x23
コード3,4のように関数化することで、別のプログラムでも利用しやすくなります。また、コード2で#uselibを使用してDLLの関数定義をしていますが、いい方法とは言えません。他のプログラムで同じ関数を定義した場合、重複定義でエラーとなります。user32.asのように一つのDLL内の関数をまとめて定義して、重複定義されないようにする必要があります。#module内に関数定義することで重複してもエラーにはなりませんが、AXファイルが大きくなることがあります。例として、3つのモジュール内で同じ関数を3つ定義していた場合のAXサイズは、753バイト、グローバルで定義した場合のAXサイズは、509バイト。防止策として、DLL関数やCOMの定義等は、モジュール外にglobalで定義する方法があります。
コード3 - main.hsp
#include "WndFunc.hsp" #define MAIN_TITLENAME "Sapmle" CreateSizeboxWnd 0, -1, -1, 300, 300 title MAIN_TITLENAME stop
コード4 - WndFunc.hsp
#ifndef WNDFUNC_HSP_ // 二重定義防止のため #define WNDFUNC_HSP_ // 二重定義防止のため #include "user32.as" #module #defcfunc SetWndStyle int st SetWindowLong hwnd, -16 , st if ( stat == 0 ){ return 0 } SetWindowPos hwnd, 0, 0, 0, 0, 0, 0x23 if ( stat == 0 ){ return 0 } return 1 #deffunc CreateSizeboxWnd int id, int x, int y, int w, int h screen id, ginfo_dispx , ginfo_dispy, 0, x, y, w, h GetWindowLong hwnd, -16 return SetWndStyle(stat | 0x50000) #global #endif // 二重定義防止のため
#addition
似た命令で、#additionがあります。これは、指定ファイルがなくてもエラーとなりません。HSPフォルダのcommon、sampleフォルダを検索してみましたが使用されているのは、hspdef.asの#addition "userdef.as" だけでした。使いどころが難しいのかあまり使われてないようです。注意
#に続く文字は、全て小文字である必要があります。大文字が含まれる場合、エラーも出ずインクルードもされないので注意。(Ver2.6はエラーになりました)コメント ( 0 ) | Trackback ( 0 )
最適化
history.txtから引用 |
|
AXファイルのサイズ比較 - HSP Ver 3.2 | |||||||||
コードを記述しない白紙の状態でAXファイルを作成した場合のサイズは、114byte。関数の定義だけでは、AXサイズは変わらず、呼び出した関数名のみ登録されます。モジュールの場合、モジュール内の命令・関数を一つでも呼び出された場合モジュール内全てが登録されるようです。
|
最適化によるラベル無効の例 | ||
モジュール内にラベルを使用している場合注意が必要です。以下サンプルです。モジュール「mod1」のラベルがモジュール「mod2」の「Func4」命令で使用されていますが、「mod1」の「Func3」命令がサンプル内で使用されていない為に最適化により「mod1」は無視されます。よって、コンパイルエラー error 19 : 致命的なエラーです
|
コメント ( 0 ) | Trackback ( 0 )
« 前ページ | 次ページ » |