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

COMオブジェクト

COMオブジェクト型変数作成命令
axobjとnewcomは、COMオブジェクトを作成します。querycomとcomeventは、既に存在するCOMオブジェクト型変数からオブジェクト型変数を作成します。
表1COMオブジェクト型変数作成命令
命令概要
axobjActiveXコントロールを作成
newcomCOMオブジェクトを作成
querycomインターフェイスを取得
comeventイベント用のインターフェイスを取得
newcom
作成モード:-1
外部関数などから得たインターフェイスポインタからオブジェクト型変数を作成
COM系命令の引数の種類
表2は、各命令で使用できる引数の種類について。oは命令が成功、xは失敗した時。 progidについては、 URLprogid - MSDN を参照。
ProgID記述例
ProgID = "Shell.Explorer.2"
CLSIDは、オブジェクトを作成する時、IIDはインターフェイスを取得する時に使用。CLSIDとIIDは、GUIDでありHSPでは文字列として扱う。また、ole32.dllのProgIDFromCLSIDやCLSIDFromProgIDで、ProgIDとCLSIDは変換可能。
guid文字列記述例
guid = "{00000000-0000-0000-C000-000000000046}"
GUIDについては、 URLGUID - Wikipedia を参照。 #usecomは、IIDとCLSIDまたはIIDからインターフェイス名の定義を行う。
#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
表2各命令に使用できる引数のテスト

ProgIDCLSID
文字列
IID
文字列
#usecom
IIDとCLSID
#usecom
IID
axobjoox
*1
ox
*4
newcomoox
*2
ox
*4
querycomx
*5
x
*3
ooo
comeventx
*5
x
*6
ox
*7
x
*7
newcom
(-1)
oooox
*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
newcom xml1, "Microsoft.XMLDOM"
xml2(0) = xml1
code2.hspは、初期化していないxml2を配列変数として代入しています。実行結果は「#Error 7 配列の要素が無効です」となります。
code3.hsp
newcom xml1, "Microsoft.XMLDOM"
dimtype xml3, 6, 4
xml3(0) = xml1
code3.hspは、dimtypeでxml3をCOMオブジェクト型変数(タイプ6)を要素4個の配列として初期化した後に、代入しています。実行結果は「#Error 39 外部オブジェクトの呼び出しに失敗しました」となります。
code4.hsp
dimtype xml4, 6, 4
newcom xml4(0), "Microsoft.XMLDOM"
newcom xml4(4), "Microsoft.XMLDOM"
code4.hspは、dimtypeで配列を確保した後newcom命令で作成しています。1回目のnewcomは成功します。2回目のnewcomは、確保した以上の要素数を指定していますが自動確保されないのでエラーが発生します。エラー内容は、「#Error 7 配列の要素が無効です」。

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 )

HSP3.3

HSP3.3を正式公開(2011/10/12) - download

変更点の一部抜粋
  • HSPスクリプトエディタのエンジン(Footy2)を更新。
  • 未初期化の変数が使用されたことを検出する機能を追加。
  • スクリプト実行速度を10~20%程度改善。
  • セキュリティ対策のためDPM暗号化のアルゴリズムを調整。

 HSP3.3より古いバージョン(HSP3.21、HSP3.22を含む)で作成された暗号化付きDPMファイルの読み取りができません。 未初期化の使用を検出されない時があります(a++など)。
コメント ( 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のみ。
表1 - モジュール作成時のAXサイズ(byte)
項目\module数012510
モジュール変数:0
モジュール関数:0
関数:0
114130146194274
モジュール変数:0
モジュール関数:0
関数:3
1142674208851,665
モジュール変数:1
モジュール関数:3
関数:0
1143656161,3752,646
モジュール変数:3
モジュール関数:3
関数:3
1145109062,1064,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から引用
2006/03/09 3.1b2
不必要なモジュール、DLLインポート情報をオブジェクトファイルから破棄する最適化機能を追加。
AXファイルのサイズ比較 - HSP Ver 3.2
コードを記述しない白紙の状態でAXファイルを作成した場合のサイズは、114byte。関数の定義だけでは、AXサイズは変わらず、呼び出した関数名のみ登録されます。モジュールの場合、モジュール内の命令・関数を一つでも呼び出された場合モジュール内全てが登録されるようです。
AX File Size : 130byte
#include "user32.as"
#module
#deffunc Func1
	return
#deffunc Func2
	return
#global
AX File Size : 226byte
#include "user32.as"
#module
#deffunc Func1
	return
#deffunc Func2
	return
#global
	Func1

AX File Size : 306byte
#include "user32.as"
#module
#deffunc Func1
	return
#deffunc Func2
	return
#global
	Func1
	Func2
	GetDesktopWindow
最適化によるラベル無効の例
モジュール内にラベルを使用している場合注意が必要です。以下サンプルです。モジュール「mod1」のラベルがモジュール「mod2」の「Func4」命令で使用されていますが、「mod1」の「Func3」命令がサンプル内で使用されていない為に最適化により「mod1」は無視されます。よって、コンパイルエラー
#ラベルが存在しません [label1@mod1]
error 19 : 致命的なエラーです
となります。コード内に、「Func3」命令がどこかにあればエラーにはなりません。
コンパイルエラーコード
#module mod1
#deffunc Func3
	return
*Label1
	return
#global

#module mod2
#deffunc Func4
	gosub *Label1@mod1
	return
#global
	Func4
コメント ( 0 ) | Trackback ( 0 )
« 前ページ 次ページ »