goo

再利用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 )

改行コード

実行環境
今回の記事内のコードはHSPの3.1と3.2のリリースバージョンで実行しています。新しいバージョンでは再現できない可能性があります。

文字コード
コード内で、クォーテンションである「'」で囲んだ時の1文字目の文字コードを意味します。つまり、

code1 = 'a'
code2 = 'ab'

上記のコードの「code1」と「code2」は同じ値が代入されます。「code1」と「code2」は、16進数整数で、0x61が代入されます。「code2」には、0x6162は代入されません。


改行コード
次に、以下のコードを実行してみます。

code1 = '¥r'
code2 = '¥n'

16進数で、「code1」に0x0d、「code2」に0x0dが代入されます。一般的には、「¥r」は、0x0d、「¥n」は、0x0aです。もし、'¥n'をコード内で書いた場合に間違った結果となる可能性があります。例を以下のコードで示します。内容は、改行の次の文字を?に変更しています。

buf = {"123
        456
        789"}

repeat strlen(buf)
	if( peek(buf, cnt) == '¥n' ){
		if( peek(buf, cnt + 1) == 0 ){ break }
		poke buf, cnt + 1, '?'
	}
loop
mes buf
上記コードのbufの結果。'¥n'の箇所に?が代入されています。
123
?456
?789

'¥n'を、0x0aに変更することで、期待したbufを取得できます。
123
?56
?89
コメント ( 0 ) | Trackback ( 0 )

XML

XML DOMメモ
※varuseでcomresの変数チェック等を省略しています。

ファイルの作成
スクリプトの文字列変数から、ファイルを作成。asyncプロパティは、1が非同期ダウンロード、0が同期。デフォルトは1。非同期の場合、loadメソッドはすべての読み込みを完了する前に戻ります。loadXMLメソッドは、指定された文字列を読み込みます。saveメソッドは、指定したファイル名に保存します。
以下のコードを実行すると、カレントフォルダに「persons.xml」ファイルを保存します。
code
sdim bufXML, 32
bufXML = "<persons><person><name>青木</name></person></persons>"
axobj XMLDoc, "Msxml2.DOMDocument", 0, 0
XMLDoc("async") = 0
XMLDoc->"loadXML" bufXML
XMLDoc->"save" "persons.xml"
font msgothic, 12
mes XMLDoc("xml")

出力ファイル:「persons.xml」
<persons><person><name>青木</name></person></persons>

ファイルの読み込み
loadメソッドは、指定したファイル名を読み込みます。
code
axobj XMLDoc, "Msxml2.DOMDocument", 0, 0
XMLDoc("async") = 0
XMLDoc->"load" "persons.xml"
font msgothic, 12
mes XMLDoc("xml")

XML宣言
以下のコードは、XML宣言<?xml version="1.0" encoding="UTF-8"?>を挿入しています。createProcessingInstructionメソッドでProcessingInstructionノードを作成(pi)して、insertBeforeメソッドで、指定したXMLDoc("firstChild")の前に挿入します。挿入前のXMLDoc("firstChild")は、「<persons/>」です。 ※mes表示では、encoding…がありませんがデータとして存在します(ファイル参照)。
code
axobj XMLDoc, "Msxml2.DOMDocument", 0, 0
XMLDoc("async") = 0
XMLDoc->"loadXML" "<persons/>"
comres pi
sdim data, 64
data = "version=¥"1.0¥" encoding=¥"UTF-8¥""
XMLDoc->"createProcessingInstruction" "xml", data
XMLDoc->"insertBefore" pi, XMLDoc("firstChild")
XMLDoc->"save" "persons.xml"
font msgothic, 12
mes XMLDoc("xml")

出力ファイル:「persons.xml」
<?xml version="1.0" encoding="UTF-8"?>
<persons/>

挿入
元データ
  <persons>
    <person>
      <name>青木</name>
      <age>24</age> 
    </person>
    <person>
      <name>川崎</name> 
      <age>18</age> 
    </person>
    <person>
      <name>坂本</name> 
      <age>32</age> 
    </person>
  </persons>
-->
挿入後のデータ
  <persons>
    <person>
      <name>青木</name>
      <age>24</age> 
    </person>
    <person type="1">
      <!-- 3要素中2番目に挿入 -->
      <name>麻生</name>
      <age>16</age> 
    </person>
    <person>
      <name>川崎</name> 
      <age>18</age> 
    </person>
    <person>
      <name>坂本</name> 
      <age>32</age> 
    </person>
  </persons>

上記の表のように挿入してみる。追加するだけならばappendChildメソッドを利用する。上記は、見やすいように字下げしています。作成されたファイルをIEで開くと整形されて表示されます。

XPathの指定
setPropertyメソッドで、SelectionLanguageプロパティをXPathに変更。デフォルトはXSLPattern。

挿入する要素の作成
createElementメソッドでperson、name、age要素を作成する。personのsetAttributeメソッドで属性を追加する。createCommentメソッドでコメント要素を作成する。personのappendChildメソッドで、コメント、name、age要素を追加する。

条件1 川崎の前に挿入したい場合
selectSingleNodeメソッドでnameが川崎のperson要素を取得する。insertBeforeメソッドで、要素を挿入する。

条件2 2番目に挿入したい場合
getElementsByTagNameメソッドでperson要素のノードリストを取得する。ノードリストのitemメソッドで2番目の要素を取得する。insertBeforeメソッドで、要素を挿入する。

code
axobj XMLDoc, "Msxml2.DOMDocument", 0, 0
XMLDoc("async") = 0
XMLDoc->"setProperty" "SelectionLanguage", "XPath"

sdim bufXML, 1024
bufXML = {"<persons>
		<person>
			<name>青木</name>
			<age>24</age>
		</person>
		<person>
			<name>川崎</name>
			<age>18</age>
		</person>
		<person>
			<name>坂本</name>
			<age>32</age>
		</person>
	</persons>"}
XMLDoc->"loadXML" bufXML

root = XMLDoc("documentElement")

// person要素数の取得
comres nodelist
root->"getElementsByTagName" "person"
lenperson = nodelist("length")

// 挿入要素の作成
comres newperson
XMLDoc->"createElement" "person"
comres resTmp
newperson->"setAttribute" "type", "1"

comres newcomment
tmpbuf = "" + lenperson + "要素中2番目に挿入"
XMLDoc->"createComment" tmpbuf
newperson->"appendChild" newcomment

comres newname
XMLDoc->"createElement" "name"
newname("text") = "麻生"
newperson->"appendChild" newname

comres newage
XMLDoc->"createElement" "age"
newage("text") = "16"
newperson->"appendChild" newage

/*
// 川崎を含むperson要素の取得
comres findperson
root->"selectSingleNode" "/persons/person[name = '川崎']"
if( varuse(findperson) ){
	root->"insertBefore" newperson, findperson
}
*/

//*
// 2番目に挿入
comres findperson
nodelist->"item" 1
root->"insertBefore" newperson, findperson
//*/

XMLDoc->"save" "persons.xml"
font msgothic, 12
mes XMLDoc("xml")

要素の削除と変更
nameが坂本のperson要素全体を削除して、nameが青木のageを20に変更します。
removeChildメソッドで削除します。ノードのテキストを変更した場合、子要素も削除されるためにitemを取得して変更しています。
code
axobj XMLDoc, "Msxml2.DOMDocument", 0, 0
XMLDoc("async") = 0
XMLDoc->"setProperty" "SelectionLanguage", "XPath"

sdim bufXML, 1024
bufXML = {"<persons>
		<person>
			<name>青木</name>
			<age>24</age>
		</person>
		<person>
			<name>川崎</name>
			<age>18</age>
		</person>
		<person>
			<name>坂本</name>
			<age>32</age>
		</person>
	</persons>"}
XMLDoc->"loadXML" bufXML

root = XMLDoc("documentElement")

// nameが坂本のperson要素を取得
comres person
root->"selectSingleNode" "/persons/person[name = '坂本']"
// 坂本の要素の親ノードを取得
parent = person("parentNode")
// 坂本の要素を削除
parent->"removeChild" person

// nameが青木のage要素を取得
comres age
root->"selectSingleNode" "/persons/person/age[//name = '青木']"
// ageの変更
child = age("childNodes")
ret = 0
repeat child("length")
	comres item
	child->"item" cnt
	if( item("nodeType") == 3 ){ // NODE_TEXT (3)
		item("text") = "20"
		ret = 1
		break
	}
loop
if( ret == 0 ){
	comres text
	XMLDoc->"createTextNode" "20"
	age->"appendChild" text
}
XMLDoc->"save" "persons.xml"
font msgothic, 12
mes XMLDoc("xml")
コメント ( 0 ) | Trackback ( 0 )

OpenClipboardのメモ

OpenClipboard について

ヘルプには、以下のように書かれています。
OpenClipboard パラメータから引用
BOOL OpenClipboard(
    HWND hWndNewOwner // ウィンドウのハンドル
);

hWndNewOwner
クリップボードをいて関連付けたいウィンドウのハンドルを指定します。NULL を指定すると、現在のタスクがクリップボードを開きます。
「クリップボードをいて」は、「クリップボードを開いて」のtypoかな。
OpenClipboard 解説から引用
他のウィンドウが既にクリップボードを開いている場合、OpenClipboard 関数は失敗します。
OpenClipboard の呼び出しに成功するたびに、アプリケーションは CloseClipboard 関数を呼び出すべきです。
EmptyClipboard 関数を呼び出さないと、hWndNewOwner パラメータで指定したウィンドウはクリップボードのオーナーになりません。


失敗するケース

OpenClipboardの引数の違い(Windows XP SP3)
処理1
処理2
結果
OpenClipboard(hWnd1)
-
成功
-
OpenClipboard(hWnd2)
or
OpenClipboard(NULL)
失敗
-
-
-
CloseClipboard()
-
成功

処理1
処理2
結果
OpenClipboard(NULL)
-
成功
-
OpenClipboard(hWnd2)
失敗
-
-
-
CloseClipboard()
-
成功
処理1
処理2
結果
OpenClipboard(NULL)
-
成功
-
OpenClipboard(NULL)
成功
-
CloseClipboard()
成功
CloseClipboard()
-
失敗

表-右下の場合、処理1のOpenClipboard(NULL)が成功しても、処理2のOpenClipboard(NULL)後は処理1のクリップボードの操作が失敗する。
コメント ( 0 ) | Trackback ( 0 )
« 前ページ 次ページ »