Re:(笑) DLLの構造体付き関数を操作するテク

 投稿者:名無しさん  投稿日:2019年 6月11日(火)03時58分3秒
   GURUGURUSMF.DLL大研究(これが本題ネ)

ども。こないだレスした者です。

 GURUGURUSMFの使用について更に深く研究してみる。
 前レスでも言った通り、BASIC系の開発環境下でこれのgetplayerstatusとgetsmfinformation
関数を使ったプログラムを繰り返し実行するとそのうちエディッタでコピペが出来なく
なってくる。実はこの現象は十進BASICでも生じる(msoのVBEほど露骨ではないが)。これ
はなぜかと考えてみた。
 ここで十進BASICヘルプに書かれている白石先生の教えを胸に復唱してみる。

○この変数の値は他の変数から代入して作成したものであってはならず,また,この変数は他の変数に代入したことのあるものであってもならない。

○引数の受け渡し方に関する規約(呼出し側は引数を逆順にスタックに積み,スタック上の引数の解放は呼び出された側が行う)はWindows APIのものと同じである。

かつてgetplayerstatusを使ったプログで、実行時にフリイズしてしまったのも、第1項の
教えに背き、前に使った文字列変数をこの関数のポインタ引数に転用してしまってたから
であろう。

 本テエマである前投稿時のサンプルプログラムで生じた不具合は、第2項の教えを守らな
かったせいではないか?
 即ちC環境下ではいざ知らず、BASIC環境下では終了時に関数が積んだスタックを開放する
ことができず、さらにそのスタックがエディッタのクリップボオドと同じメモリ領域を使用
しているのだ。そう考えが及んだ。
 問題の関数、は構造体を引数に使っているが、
構造体といっても実は4バイト整数型変数を5つ、9つ並べただけなので、なんと文
字列変数で代用することができる。
 そこで先ず、プレイリスト(musicID)を開放するために、clearlistという関数を利用する
 修正すると、こうだ(前レス時のサンプルもちょっと間違ってた)。

OPTION CHARACTER byte
LET q=op(-1100,0)          !第1引数は-1100(directmusic)か-1(win mapper)
LET q=al("e:\落ちゲー\data\music\net.mid",0,2)    !MIDIは任意のMIDIフアイル名、フアイルIDは第3引数
LET q=pl(0,2,0,0,0)    !フアイルIDは第2引数
DO
   WAIT DELAY 1
   LET q$=REPEAT$(" ",20)
   CALL gs(q$,20)     !第2引数は20(getplayerstatus),36(getsmfinformation)固定
   IF ORD(left$(q$,1))=0THEN     !終了が0,再生中が1,一時停止中が2
      CALL st(0)
      EXIT DO
   END IF
LOOP
call ci   !修正部分!
CALL cl      !プログラム終了前に必ずClosedeviceしないとフリイズするので注意
END
EXTERNAL SUB ci                                                 !修正部分!
assign"c:\gurugurusmf4-0-6\gurugurusmf4.dll","GGS4ClearList"    !修正部分!
END SUB                                                         !修正部分!
EXTERNAL FUNCTION op(q,w)
assign"c:\gurugurusmf4-0-6\gurugurusmf4.dll","GGS4OpenDevice"    !関数識別冠詞「GGS4」は必ず必要
END FUNCTION
EXTERNAL FUNCTION al(q$,w,e)
assign"c:\gurugurusmf4-0-6\gurugurusmf4.dll","GGS4AddListFromFileA"
END FUNCTION
EXTERNAL FUNCTION pl(q,w,e,r,t)
assign"c:\gurugurusmf4-0-6\gurugurusmf4.dll","GGS4Play"
END FUNCTION
EXTERNAL SUB cl
assign"c:\gurugurusmf4-0-6\gurugurusmf4.dll","GGS4CloseDevice"
END SUB
EXTERNAL SUB gs(q$,w)
assign"c:\gurugurusmf4-0-6\gurugurusmf4.dll","GGS4GetPlayerStatus"
END SUB
EXTERNAL SUB st(q)
assign"c:\gurugurusmf4-0-6\gurugurusmf4.dll","GGS4Stop"
END SUB

これでも未だ解決しない。そこでGetPlayerStatus関数が使用時ごとに積んだで
あろうスタックの開放を試みる。

OPTION CHARACTER byte
LET q=op(-1100,0)          !第1引数は-1100(directmusic)か-1(win mapper)
LET q=al("e:\落ちゲー\data\music\net.mid",0,2)    !MIDIは任意のMIDIフアイル名、フアイルIDは第3引数
LET q=pl(0,2,0,0,0)    !フアイルIDは第2引数
DO
   WAIT DELAY 1
   LET q$=REPEAT$(" ",20)
   CALL gs(q$,20)     !第2引数は20(getplayerstatus),36(getsmfinformation)固定
   IF ORD(left$(q$,1))=0THEN     !終了が0,再生中が1,一時停止中が2
      CALL st(0)
      EXIT DO
   END IF
   LET q$=""    !修正部分!
LOOP
LET q$=""    !修正部分!
call ci   !修正部分!
CALL cl      !プログラム終了前に必ずClosedeviceしないとフリイズするので注意
END
EXTERNAL SUB ci                                                 !修正部分!
assign"c:\gurugurusmf4-0-6\gurugurusmf4.dll","GGS4ClearList"    !修正部分!
END SUB                                                         !修正部分!
EXTERNAL FUNCTION op(q,w)
assign"c:\gurugurusmf4-0-6\gurugurusmf4.dll","GGS4OpenDevice"    !関数識別冠詞「GGS4」は必ず必要
END FUNCTION
EXTERNAL FUNCTION al(q$,w,e)
assign"c:\gurugurusmf4-0-6\gurugurusmf4.dll","GGS4AddListFromFileA"
END FUNCTION
EXTERNAL FUNCTION pl(q,w,e,r,t)
assign"c:\gurugurusmf4-0-6\gurugurusmf4.dll","GGS4Play"
END FUNCTION
EXTERNAL SUB cl
assign"c:\gurugurusmf4-0-6\gurugurusmf4.dll","GGS4CloseDevice"
END SUB
EXTERNAL SUB gs(q$,w)
assign"c:\gurugurusmf4-0-6\gurugurusmf4.dll","GGS4GetPlayerStatus"
END SUB
EXTERNAL SUB st(q)
assign"c:\gurugurusmf4-0-6\gurugurusmf4.dll","GGS4Stop"
END SUB

 即ち、構造体の代わりに使った単独文字列変数 q$ に、空の文字列 "" を
代入してやるのだ。これで見事に解決し、エディッタ使用時の不具合も無く
なった!
 ここにおいて、やはりこのq$はBASICが自由に使える文字列変数ではなくて、
システム・メモリに制約された「ポインタ」なのだと改めて実感した。
 なお、「q$=""」は上記の通り、終了時だけでなくgetplayerstatus関数使用
ごとに実行しなければならない事に、 注意。

 さらに、同じ事をMSO VBAでやるには,
 文字列変数は常に半角全角混合文字として扱われるため(即ち十進における
OPTION CHARACTER BYTE 状態にできない)ため、q$の代わりにVB版構造体、ユウザア定義型変数
を下記のように定義し(てゆうかこっちの方が普通か)、

Private Type ruct
q As Long   ←構造体識別子名は何でもいーらしい
w As Long
e As Long
r As Long
t As Long
End Type

実行プロシイジャ上で,getplayer関数の構造体解放時に

q.q=Empty:q.w=Empty:q.e=Empty:q.r=Empty:q.t=Empty
(Emptyは十進Bの""に相等)

のよーにユウザア定義型変数の要素ごとに個別に解放しなければならない。



                               P.S.1

 あー苦労した。こんな事C++やC#ではラクラクできるのだろーが。高価な開発
環境下では達成できて当たり前。十進BASICのような見かけ上安っぽい(私はそーは
思ってないが)環境下でも達成できてこそ真のエンジニアダ!

                               P.S.2

 上記のVBAの例、Office 2000やOffice 2003のよーな古いverでの話。今のOffice
ではさらにPtrとかいう値を使わないとエラアになるらしー。

                               P.S.3

 十進BASICのデバッガはバグがひどくて困りますな(VER7.6.6の話だが)。プログラム
のデバッグ中、DEBUG窓の精度が悪いため、BASIC言語自身のバグと思い込み、この掲示板に
修正依頼を出そーとした事数度。結局全部私の入力ミスが原因だった訳だが。その原因はほかの
方法で知ったもの。BASICアプリそのものの動作は、全幅の信頼を置けるレベルだけに残念無念。
 

戻る