3

.Net プログラミングについて私が知っているすべてのことから、ここで見られる動作は完全に不可能であることがわかります。それで、誰かがここで何が起こっているのか説明してもらえますか? 簡単なコード:

Structure WKSTA_USER_INFO_1
    Dim wkui1_username As Integer
    Dim wkui1_logon_domain As Integer
    Dim wkui1_logon_server As Integer
    Dim wkui1_oth_domains As Integer
End Structure

Declare Function NetWkstaUserGetInfo Lib "Netapi32" (ByVal reserved As Integer, ByVal level As Integer, ByRef lpBuffer As Integer) As Integer
Declare Sub lstrcpyW Lib "kernel32" (ByRef dest As Byte, ByVal src As Integer)
Declare Sub RtlMoveMemory Lib "kernel32" (ByRef dest As WKSTA_USER_INFO_1, ByRef src As Integer, ByVal Size As Integer)
Declare Function NetApiBufferFree Lib "Netapi32" (ByVal Buffer As Integer) As Integer

Function GetDomain() As String
    Dim ret As Integer
    Dim wk1 As WKSTA_USER_INFO_1
    Dim pwk1 As Integer

    Dim test As String = ""

    ret = NetWkstaUserGetInfo(Nothing, 1, pwk1)
    RtlMoveMemory(wk1, pwk1, Len(wk1))

    ret = NetApiBufferFree(pwk1)

    Return "test"
End Function

ここにブレーク ポイントを配置すると、RtlMoveMemory の後、wk1 にユーザー名へのポインターが含まれ、他のすべてが 0 であることがわかります。これは一貫しています。ここで、変更Dim test As String = ""Dim login As String = ""て再度実行すると、wk1 には username と logon_domain の両方へのポインターが含まれています。

に変更するとDim login As String、ユーザー名のみへのポインターが含まれます。その(完全に未使用の)変数名を何に変更するかによって、異なる結果が得られます。これはどのように可能ですか?

私はいつも、変数の名前を何にするかは重要ではないという印象を受けてきました。そして、変数を宣言してからそれを使用しないことは、そこに変数をまったく持たないこととは異なります。

私はこれを2台のコンピューターで試しましたが、一貫した結果が得られました(.Net 3.5で1つ、4.0で1つ)。しかし、C# に変換しようとすると、再現できませんでした。

ちなみに、System.Environment を使用するだけで、現在のユーザー情報について必要なものを取得できることはわかっています。これは自動的にアップグレードされた古い VB6 コードでした (より簡単にするために少し編集しました)。この動作がどのように可能であるかを理解しようとしています。明らかに、私は何年もかけて .Net について何かを仮定してきましたが、それはまったく真実ではありません。

4

1 に答える 1

1

解決策、レイモンド・チェンの助けを借りて:

RtlMoveMemoryの宣言では、srcをByRefではなくByValとして渡す必要があります。渡すsrcはメモリ位置へのポインタであるため、ByRefを渡すと、ポインタが格納されていた場所のメモリアドレス、つまり変数宣言の場所が渡されます。したがって、他の変数または異なる名前の変数を使用すると、異なる結果が生成されます。

元のVB6コードでByRef...が渡された理由に関するメモでは、宣言でByValが指定されておらず、ByRefがVB6のデフォルトです。したがって、宣言自体はByRefを期待していました。ただし、APIの呼び出しでは、変数ByValを渡すように指定されていました。これは、.Netでは実行できないことです。宣言が期待しているのと同じようにそれを渡す必要があります。そのため、自動アップグレード機能はByRefを宣言に追加しました。これにより、宣言はVB6と同じに保たれますが、呼び出しでByValが無視されます。

于 2012-05-22T17:07:09.083 に答える