C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[5]: GetPrivateProfileStringにつきまして


(過去ログ 21 を表示中)

[トピック内 8 記事 (1 - 8 表示)]  << 0 >>

■8907 / inTopicNo.1)  GetPrivateProfileStringにつきまして
  
□投稿者/ ことぶき (1回)-(2007/10/12(Fri) 22:47:57)

分類:[VB6 以前] 

はじめまして。
visual stadio6.0を使用しています。
vb6.0に関しての質問です。

ネイティブはjavaなのですがこの度、vbをさわる機会に恵まれました。
既存のソースを眺めていて疑問が湧き、自分では解決に至りませんでしたので、
申し訳ありませんが力を貸してください。

ソースにGetPrivateProfileStringを使うものがありました。
その第四引数に指定したstringの変数にiniファイルの該当部分が格納されているようです。

********************************ソースイメージ(環境が無いので検証はできていません)***********
Dim hoge as string * 1024
Dim piyo as long
Dim bar = string
piyo = GetPrivateProfileString("キー","セクション","",hoge,(length),(iniファイル名))
bar = hoge
******************************************************************************************

しかし、呼び出し先のGetPrivateProfileString()メソッドの第四引数はbyValが指定されています。
#これは値渡しの指定ですよね?
また、vb6.0ではstringはオブジェクト型ではないとの記述をwebで見ました。
その為、アドレスを引数に渡しwinAPI側でアドレスの参照先を変更しているのではないと思っています。

しかし、私の意に反して多くの(私が見た)解説ページでは当然のことのように説明が省かれています。

何故、上記変数barにiniファイルの値が入るのでしょうか?

#質問自体にいたらない点などありましたらお詫び申し上げます。

引用返信 編集キー/
■8921 / inTopicNo.2)  Re[1]: GetPrivateProfileStringにつきまして
□投稿者/ Starfish (1回)-(2007/10/13(Sat) 16:30:41)
No8907 (ことぶき さん) に返信
> しかし、呼び出し先のGetPrivateProfileString()メソッドの第四引数はbyValが指定されています。
> #これは値渡しの指定ですよね?
> また、vb6.0ではstringはオブジェクト型ではないとの記述をwebで見ました。
> その為、アドレスを引数に渡しwinAPI側でアドレスの参照先を変更しているのではないと思っています。
> 
> しかし、私の意に反して多くの(私が見た)解説ページでは当然のことのように説明が省かれています。

 Windows API の関数を呼ぶ時は、文字列は値渡しで行います。詳しくは、ヘルプを
参照してください。

Visual Studio 6.0 ドキュメント
+ Visual Basic ドキュメント
 + Visual Basic の使用方法
  + コンポーネント ツール ガイド
   + DLL および Windows API へのアクセス
    + DLL プロシージャへの文字列の引き渡し

引用返信 編集キー/
■8934 / inTopicNo.3)  Re[1]: GetPrivateProfileStringにつきまして
□投稿者/ ぶっちゃん (1回)-(2007/10/14(Sun) 15:30:48)
No8907 (ことぶき さん) に返信

> 何故、上記変数barにiniファイルの値が入るのでしょうか?
え?
> bar = hoge
ってやってるからじゃないの?
引用返信 編集キー/
■8941 / inTopicNo.4)  Re[2]: GetPrivateProfileStringにつきまして
□投稿者/ ことぶき (3回)-(2007/10/15(Mon) 00:06:37)
Starfishさん、ぶっちゃんさんレスありがとうございます。

>Starfishさん
> Windows API の関数を呼ぶ時は、文字列は値渡しで行います。詳しくは、ヘルプを
>参照してください。

***************ことぶきの書き込み********************

しかし、呼び出し先のGetPrivateProfileString()メソッドの第四引数はbyValが指定されています。
#これは値渡しの指定ですよね?
また、vb6.0ではstringはオブジェクト型ではないとの記述をwebで見ました。
その為、アドレスを引数に渡しwinAPI側でアドレスの参照先を変更しているのではないと思っています。

****************************************************

にあるとおり値渡しであることは分かりました。
分からないのは「これは参照渡しの挙動では?なんでhogeの値が変わるの?」ということです。
ヘルプに関するご指摘ありがとうございます。
明日(今日?)早速調べてみます。(何を調べてよいかも分からない状態でした。)

>ぶっちゃんさん
>> 何故、上記変数barにiniファイルの値が入るのでしょうか?
>え?
>> bar = hoge
>ってやってるからじゃないの?

おそらくそうなのでしょうが、私には理由が分かりませんでした。
hoge(上記ソースイメージには書き忘れてしまいましたが初期化をしただけの変数です。)
はどの段階で書き換えられているのですか?
vb6では当然の挙動なのかもしれませんが値渡しで渡した引数が書き換えられて戻ってくる(≠戻り値)事に
相当違和感を感じています。

「この情報がないとわからない。」
など私が書き忘れていることがございましたら併せてご指摘ください。
宜しくお願いいたします。

引用返信 編集キー/
■8942 / inTopicNo.5)  Re[3]: GetPrivateProfileStringにつきまして
□投稿者/ Starfish (2回)-(2007/10/15(Mon) 01:34:35)
No8941 (ことぶき さん) に返信
> にあるとおり値渡しであることは分かりました。
> 分からないのは「これは参照渡しの挙動では?なんでhogeの値が変わるの?」ということです。
> ヘルプに関するご指摘ありがとうございます。
> 明日(今日?)早速調べてみます。(何を調べてよいかも分からない状態でした。)

 VBの文字列はUNICODEですがWindowsではANSIです。(UNICODEのインターフェースもありますが
VBから使うときは一般的にはANSIのものを使います。)

 なので、動作的には、値渡しでも参照渡しでもありません。Byval をつけるのは、深く考えずに
そういう決まりだと考えたほうがいいと思います。

> bar = hoge

 これでは、hogeの1024文字分のデータがコピーされるので、barには後ろにごみのデータが
ついています。ヘルプにも記載されていますが以下のようにしてNULL以降のデータを削除する
必要があります。

bar = Left(hoge, InStr(hoge, Chr$(0))-1)

引用返信 編集キー/
■8943 / inTopicNo.6)  Re[3]: GetPrivateProfileStringにつきまして
□投稿者/ 魔界の仮面弁士 (469回)-(2007/10/15(Mon) 05:08:37)
No8941 (ことぶき さん) に返信
> vb6では当然の挙動なのかもしれませんが値渡しで渡した引数が書き換えられて戻ってくる(≠戻り値)事に
> 相当違和感を感じています。
確かに通常は、「値渡し」で内容が書き変わる事は無いのですが、Declare ステートメントを
使っている場合は、API 側でそのポインタの示す文字列の内容を編集する事ができるのです。

これは、文字列型変数が『文字列へのポインタ』として管理されているという事情によるものです。
(BSTR は、OLE ヘッダ ファイルでは OLECHAR FAR * として定義されます)

なお、Declare にて、文字列を参照渡しするのは、(LPSTRではなく)BSTRを受け取る場合だけです。

ついでに書いておくと、Declare では、文字列の ANSI/Unicode 変換も同時に行われるため、
文字列型では LPWSTR を受け取ることが出来ません。そのため、Unicode 文字列を渡す場合は、
バイト配列を使って渡すのが慣例となっています。(または、アドレスを値渡しする方法もあり)


より細かい内容について知りたいのであれば、MSDN ライブラリの
[MSDN ライブラリ 2001 年 4 月]
└[技術情報]
 └[技術情報 (日本語)]
  └[ビジュアル ツール]
   └[Visual Basic]
    └[Visual Basic]
     └[Microsoft Visual Basic Version 5.0 で使用する DLL の開発に関する注意]
を参照してみてください。




以下、No8921で紹介されている内容に絡めた、String 型に関する実験コード。

変数のアドレスを取得する「VarPtr 関数」と、
文字列のアドレスを取得する「StrPtr 関数」を使っています。

'----------------------
Option Explicit

Private Declare Sub RtlMoveMemory Lib "KERNEL32" _
   (ByRef hpvDest As Any, _
    ByVal hpvSource As Long, _
    ByVal cbCopy As Long)

Private Sub Command1_Click()
    Dim S As String, bin() As Byte
    S = Text1.Text
    bin = S

    Debug.Print "============="
    Debug.Print "変数Sの文字列の長さ:="; Len(S); "(文字数)"
    Debug.Print "変数Sの内容:=「"; S; "」"
    Debug.Print "変数Sのバイナリ:=「"; DumpStr(bin); "」"

    Dim pVar As Long, pStr As Long
    pVar = VarPtr(S)
    pStr = StrPtr(S)

    Debug.Print "============="
    Debug.Print "VarPtr(S):="; Hex(pVar); ":変数S のアドレス"
    Debug.Print "StrPtr(S):="; Hex(pStr); ":文字列のアドレス"

    Dim pVarValue As Long, size As Long
    pVarValue = ReadLong(pVar)
    size = ReadLong(pStr - 4)

    Debug.Print "============="
    Debug.Print Hex(pVarValue)
    Debug.Print "  = ReadLong(VarPtr(S))"
    Debug.Print "  これは、StrPtr(S) と一致する"
    Debug.Print "  文字列変数の場合、VarPtrはStrPtrへのポインタを指す"
    Debug.Print CStr(size)
    Debug.Print "  = ReadLong(StrPtr(S) - 4)"
    Debug.Print "  これは、文字数の2倍と一致する"
    Debug.Print "  StrPtrの直前4バイトには、文字列のバイト数が格納されている"
    Debug.Print Dump(pStr, size)
    Debug.Print "  = Dump(pStr, バイト数)"
    Debug.Print "  これは変数 S のバイナリと一致する"
    Debug.Print "  StrPtrからのアドレスには、文字列本体が格納されている"
End Sub

Private Function ReadLong(ByVal Ptr As Long) As Long
    RtlMoveMemory ReadLong, Ptr, 4
End Function

Private Function Dump(ByVal Ptr As Long, ByVal Length As Long) As String
    Dim n As Long, b() As Byte
    If Length > 0 Then
        ReDim b(Length - 1)
        RtlMoveMemory b(0), Ptr, Length
        For n = 0 To Length - 1
            Dump = Dump & Right("00" & Hex(b(n)), 2) & " "
        Next
    End If
End Function

Private Function DumpStr(ByRef bin() As Byte) As String
    Dim v As Variant
    For Each v In bin
        DumpStr = DumpStr & Right("00" & Hex(v), 2) & " "
    Next
End Function

Private Sub Form_Load()
    Text1.Text = "あいうえお"
End Sub

引用返信 編集キー/
■8982 / inTopicNo.7)  Re[4]: GetPrivateProfileStringにつきまして
□投稿者/ ことぶき (4回)-(2007/10/15(Mon) 21:28:07)
Starfishさん、魔界の仮面弁士さんレスありがとうございます。
また、レス/お礼が遅くなり申し訳ありません。

>Starfishさん
>なので、動作的には、値渡しでも参照渡しでもありません。Byval をつけるのは、深く考えずに
そういう決まりだと考えたほうがいいと思います。

私も最初はそう考え、作業を進めていたのですがどうしても気になってしまい、
今回質問するに至りました。

>魔界の仮面弁士さん
「Microsoft Visual Basic Version 5.0 で使用する DLL の開発に関する注意」
はググって見つけることが出来ました。

疑問に思っていた事にお答えいただきありがとうございます。
とてもすっきりしました。

また、実験コードのご提示までしていただきありがとうございます。
何をするコードなのかしっかり理解した上で実行してみたいと思います。

>お付き合いいただいた方々
皆さんのおかげで疑問を解消する事が出来ました。ありがとうございます。

解決済み
引用返信 編集キー/
■8983 / inTopicNo.8)  Re[5]: GetPrivateProfileStringにつきまして
□投稿者/ 魔界の仮面弁士 (472回)-(2007/10/15(Mon) 21:38:42)
一応補足。

No8982 (ことぶき さん) に返信
> >魔界の仮面弁士さん
> 「Microsoft Visual Basic Version 5.0 で使用する DLL の開発に関する注意」
> はググって見つけることが出来ました。

オンライン版だと、このあたりですね。
http://www.microsoft.com/japan/msdn/vs_previous/vbasic/docs/dll/
解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -