
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++ ならではのオブジェクティブな言語仕様は理解していません。
へんな質問かも知れませんが、よろしくお願いします。
No.1ベストアンサー
- 回答日時:
Win32APIに文字列を渡すには、ヌルで終端された文字列の先頭アドレスを指定します。
つまり、Cでいうところの char[] を渡します。
それに対してVBのString型は、直接には文字列データを持っていません。
String型変数には、文字列の先頭アドレスと文字列の長さが入っていて、本当の文字列データはどこか別の所に有ります。(VBが自動的にAlocateしたメモリに入る)
なので、String型変数のByRefを取って渡しても、APIは正しい文字列データを取得できません。
それに対してString型変数のByValを取ると、文字列の先頭アドレスが取得できるので、APIにそのまま渡せます。
この回答への補足
ご回答まことに有り難うございます。
まず自分の質問の訂正です。
"【質問】" のエリアの "ByRef"(3箇所)は "ByVal" の間違いです(恥)
申し訳ありません。
Basicの文字列変数の内部での持ち方、なんとなく思い出してきました。Basicをやっていたのは8bitの時代のことだったので、すっかり忘れていました。文字列変数の内部表現は今でも昔のそれを引き継いでいるのですね。
もう一つの疑問の APIのDLL と 自作DLL との違いですが、APIは確かPASCAL I/F でしたっけ。それに対して自分のDLLは extern "C" とかやっていたような気が... 同じDLLでも違う I/F になっている気がしてきました。
どうもVBAのDeclare文のところで、色んなI/Fへの辻褄あわせがなされているようですね。
もう少し色んな方の回答を待ってみます。
有り難うございました。
ご回答まことに有り難うございました。
またお礼が遅くなりすみません。
自分でちゃんと調べたいとは思うのですが、昔ほどのヒマも気力もなく、今はANo.2の方の補足に書いたような、私の勝手な解釈でとりあえず納得することにしました。
Basicの文字列変数の内部形式を思い出させて頂きました。(もしかしてVBやVBAは違うかも?)
有り難うございました。
No.2
- 回答日時:
VB6とVC6を使用していたころ私もこれが気になり調べたことがあります。
#確か、VB6の場合は、Win32APIにStringを渡す場合に一度(内部で)変換しているので、記述としてはByValで、内部の変換後は結果的にAPIに対してByRefになっていたような記憶があります。
それらしい記述を探してみましたが、明確に書いたのもを見つけられませんでした。
以下のサイトに一部それらしい記述があります。
http://www5.ocn.ne.jp/~kansroom/vbtips/waza14.htm
ただ、EXCEL VBAでも同様かまでは判りません
この回答への補足
ご回答まことに有り難うございます。
まず自分の質問の訂正です。
"【質問】" のエリアの "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.1の方の回答と優劣は付けられなかったのですが、先に回答下さったとの理由でANo.1の方に20ポイントとしたことを、ご了承下さい。
有り難うございました。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# c言語 コマンドライン引数 4 2023/02/09 18:47
- システム CSVファイルのマッピング処理の省力化 1 2022/11/24 00:01
- Excel(エクセル) Excelの関数について 3 2022/11/13 23:47
- C言語・C++・C# 関数ポインタの高速化のメリット 7 2023/05/05 20:15
- Visual Basic(VBA) VBA初心者です 検索した数字の行に色をつける 5 2023/02/13 14:22
- Excel(エクセル) Excel 、この式はどのように解釈すればいいのでしょうか 4 2023/02/03 08:53
- C言語・C++・C# const char** p;のとき、free(p)でC4090エラーとなるのはなぜですか 3 2023/03/31 16:28
- Visual Basic(VBA) Vbaで数式をポーランド記法に変換するコードを作って実行しようとするとフリーズします。 1 2022/05/24 17:53
- Excel(エクセル) エクセルVBA、ファイル名をセルの値で保存の方法を教えてください。 おそれいります。こちらで数々のエ 6 2023/06/30 22:17
- Visual Basic(VBA) 【再々投稿】VBAのプログラムで動作しなくて困っています 8 2022/10/14 09:06
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
エクセルでアルファベットか数...
-
VBAでの Replace関数で、ワイル...
-
EXCELで=より左の文字を一括で...
-
【Excel VBA】複数ある特定の文...
-
16表記の文字列を数字に直した...
-
VBA2005 16進を2桁で表示したい。
-
変数に入れた文字列(定数)で書...
-
OnTime 使用時のプロシージャへ...
-
文字列からタブコードを取り除...
-
エクセルで文字列の最大値を抽...
-
LEFT関数で文字数を指定しない...
-
Excelで3E8を3.00E+8にしない方...
-
エクセルVBAで特定の文字列が見...
-
ヒアドキュメントのEOLとEOMの違い
-
C++のdefine文の使い方の質問で...
-
漢数字に変換するプログラム
-
C# 巨大な文字列の計算をさせたい
-
Excelで指数表現しないようにす...
-
アクセスで特定の数字以外(複...
-
bashスクリプトでの文字列から...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
エクセルでアルファベットか数...
-
EXCELで=より左の文字を一括で...
-
文字列からタブコードを取り除...
-
VBAでの Replace関数で、ワイル...
-
エクセルで文字列をtxtファイル...
-
【Excel VBA】複数ある特定の文...
-
エクセル 数値データを桁をそ...
-
Excelで3E8を3.00E+8にしない方...
-
VBA2005 16進を2桁で表示したい。
-
エクセルで文字列の最大値を抽...
-
同一セル内に関数と文字列を同...
-
Left関数とRight関数を合わせた...
-
Excelで指数表現しないようにす...
-
MS SQLServer のSQLで文字列の...
-
VBの「As String * 128」とは?
-
エクセルでセル内の文字列の最...
-
ORCLEでの小数の表示方法の変更...
-
bashスクリプトでの文字列から...
-
LEFT関数で文字数を指定しない...
-
アクセスで特定の数字以外(複...
おすすめ情報