全然更新しないブログ
HSPメモ帳
ファイルハンドルからファイル名を取得
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" }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
}
}
stopCOMオブジェクトの破棄
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
stopcnvstow
cnvstow
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
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 関数の動作は未定義です。
strncpy 関数は、strSource の最初の count の文字数を strDest にコピーし、strDest を返します。count で指定した文字数が strSource の文字数より少ない場合、NULL 文字はコピー先の文字列に追加されません。count で指定した文字数が strSource の文字数よりも多い場合は、count の文字数になるまで、コピー先文字列に NULL 文字が埋め込まれます。コピー元の文字列とコピー先の文字列が重なり合う場合、strncpy 関数の動作は未定義です。
とあります。大きなサイズや頻繁に代入が必要なクローン文字列変数を使う場合、代入は使わないでmemcpyなどを使用したほうがいいかと思います。
逆に、常にクリアしたい時は便利かもしれません(固定バッファサイズの文字列を送信する時など)。
再利用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
#endifAXファイルサイズ
関数は、#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
| « 前ページ |
