- ベストアンサー
Excel VBA で Win32API CreateFileA などの String型引数は、なぜ ByVal?
Excel VBA から Win32API を実行する場合の、String型引数に関する質問です。 【背景】 Win32API の CreateFileA,MoveFileA,DeleteFileA など、関数名最後が "A" となている関数の String型引数は、全て Declare文で ByVal と宣言しないと上手く動作しません。 しかし VisualC++ のヘッダファイルでこれらの "A" 付き API の宣言を見てみると、文字列型の引数は全てアドレス渡しとして宣言されています。BVA での上記の宣言と矛盾しており、ByVal で上手く動作するのが不思議でなりません。 また VC++ で自分で作成した DLL関数の文字列型引数の場合は、BVA のDeclare文で ByRef と宣言しなければ上手く動作しません。これは上記の VC++ ヘッダファイルの API関数の宣言と辻褄が合っており、やはり、Declare文で "A"付き APIの場合に ByVal としなければならない事が矛盾しているとしか思えません。 【質問】 いったいこれは、どうなっているのでしょうか?? この場合("A" 付き API の場合)、どうして ByRef でちゃんと動くのでしょうか? また String型の場合 ByRef では効率が悪いと思うのですが、なぜ ByRef が採用されているのでしょうか? サルにでも分かるように説明して頂ければ幸いです。 【私の知識レベル】 C++ ではなく C言語 においては、アセンブラレベルでのコード及び動作を理解しております。 オブジェクト,クラス,メソッドなどの用語は一応理解しているつもりですが、C++ ならではのオブジェクティブな言語仕様は理解していません。 へんな質問かも知れませんが、よろしくお願いします。
- みんなの回答 (2)
- 専門家の回答
質問者が選んだベストアンサー
Win32APIに文字列を渡すには、ヌルで終端された文字列の先頭アドレスを指定します。 つまり、Cでいうところの char[] を渡します。 それに対してVBのString型は、直接には文字列データを持っていません。 String型変数には、文字列の先頭アドレスと文字列の長さが入っていて、本当の文字列データはどこか別の所に有ります。(VBが自動的にAlocateしたメモリに入る) なので、String型変数のByRefを取って渡しても、APIは正しい文字列データを取得できません。 それに対してString型変数のByValを取ると、文字列の先頭アドレスが取得できるので、APIにそのまま渡せます。
その他の回答 (1)
- equinox2
- ベストアンサー率48% (321/660)
VB6とVC6を使用していたころ私もこれが気になり調べたことがあります。 #確か、VB6の場合は、Win32APIにStringを渡す場合に一度(内部で)変換しているので、記述としてはByValで、内部の変換後は結果的にAPIに対してByRefになっていたような記憶があります。 それらしい記述を探してみましたが、明確に書いたのもを見つけられませんでした。 以下のサイトに一部それらしい記述があります。 http://www5.ocn.ne.jp/~kansroom/vbtips/waza14.htm ただ、EXCEL VBAでも同様かまでは判りません
お礼
ご回答まことに有り難うございました。 またお礼が遅くなりすみません。 自分でちゃんと調べたいとは思うのですが、昔ほどのヒマも気力もなく、今は補足に書いたような勝手な解釈で、とりあえず納得することにしました。 ANo.1の方の回答と優劣は付けられなかったのですが、先に回答下さったとの理由でANo.1の方に20ポイントとしたことを、ご了承下さい。 有り難うございました。
補足
ご回答まことに有り難うございます。 まず自分の質問の訂正です。 "【質問】" のエリアの "ByRef"(3箇所)は "ByVal" の間違いです(恥) 申し訳ありません。 BasicのDeclare文の箇所では、Basic以外の色んなI/Fへの辻褄あわせが内部でなされているということ、なんとなく分かってきました。有り難うございます。 また ANo.1の方への補足にも書きましたが、自作のDLLはAPIのDLLとは I/Fが違っているような気がしてきました。自作では extern "C" とかしていたような気がします。 どうも Declare文での(少なくとも文字列型変数の)ByVal,ByRefは、本来の意味で解釈しない方が良さそうですね。 今の所の自分なりの解釈としては、文字型変数で ByValとあれば API向けのI/F合わせを、ByRefとあれば CライクなI/F合わせをしているのかなと。 もう少し色んな方の回答を待ってみます。 有り難うございました。
お礼
ご回答まことに有り難うございました。 またお礼が遅くなりすみません。 自分でちゃんと調べたいとは思うのですが、昔ほどのヒマも気力もなく、今はANo.2の方の補足に書いたような、私の勝手な解釈でとりあえず納得することにしました。 Basicの文字列変数の内部形式を思い出させて頂きました。(もしかしてVBやVBAは違うかも?) 有り難うございました。
補足
ご回答まことに有り難うございます。 まず自分の質問の訂正です。 "【質問】" のエリアの "ByRef"(3箇所)は "ByVal" の間違いです(恥) 申し訳ありません。 Basicの文字列変数の内部での持ち方、なんとなく思い出してきました。Basicをやっていたのは8bitの時代のことだったので、すっかり忘れていました。文字列変数の内部表現は今でも昔のそれを引き継いでいるのですね。 もう一つの疑問の APIのDLL と 自作DLL との違いですが、APIは確かPASCAL I/F でしたっけ。それに対して自分のDLLは extern "C" とかやっていたような気が... 同じDLLでも違う I/F になっている気がしてきました。 どうもVBAのDeclare文のところで、色んなI/Fへの辻褄あわせがなされているようですね。 もう少し色んな方の回答を待ってみます。 有り難うございました。