Windows API根据未使用变量的名称导致不同的结果?

时间:2012-04-05 19:59:17

标签: .net vb.net winapi memory

我所知道的一切.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上,一个在4.0上)。但是,当我尝试将其转换为C#时,我无法重现它。

顺便说一句,我知道我可以使用System.Environment获取当前用户信息所需的内容;这是自动升级的旧VB6代码(我编辑了一点以使其更加简单)。我只想了解这种行为是如何实现的。显然,我花了很多年时间假设某些关于.Net的事情并不完全正确。

1 个答案:

答案 0 :(得分:1)

解决方案,在Raymond Chen的帮助下:

RtlMoveMemory的声明应该将src作为ByVal传递,而不是ByRef。因为我传递的src是一个指向内存位置的指针,传递它ByRef导致它传递我的指针存储位置的内存地址...换句话说,我的变量声明的位置。因此,使用其他变量或不同命名的变量会产生不同的结果。

关于为什么在原始VB6代码中传递ByRef ...的注释,它没有在声明中指定ByVal,而ByRef是VB6中的默认值。因此,声明本身就是期待ByRef。但是,对API的调用指定它传递变量ByVal。这是你在.Net中无法做到的事情;你必须传递它与声明所期望的相同。因此,自动升级程序将ByRef添加到声明中,声明保持声明与VB6相同,但它忽略了调用中的ByVal。