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

.net Windows API会根据未使用变量的名称导致不同的结果吗?,.net,vb.net,winapi,memory,.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

我所知道的关于.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
当我在这里放一个断点时,我看到在rtlmovemory之后,我的wk1包含一个指向用户名的指针,而所有其他的都是0。这是一致的。现在,如果我将
Dim test更改为String=“”
并再次运行,wk1将同时包含指向用户名和登录域的指针

如果我将其更改为
Dim login As String
,则它只包含指向用户名的指针。根据我将(完全未使用的)变量名更改为什么,我会得到不同的结果。这怎么可能


我一直有这样的印象,选择什么来命名变量并不重要。声明一个变量,然后再也不使用它,这与根本没有变量是不可能的

我在两台计算机上试过,结果一致(一台在.NET3.5上,一台在4.0上)。然而,当我尝试将其转换为C#时,我无法复制它


顺便说一句,我知道我可以使用System.Environment获取我需要的关于当前用户信息的信息;这是自动升级的旧VB6代码(我对其进行了一些编辑,使其更简单)。我只是想了解这种行为是怎么可能的。显然,我花了很多年的时间对.Net进行了一些不完全正确的假设。

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

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


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

“声明一个变量,然后再不使用它,与根本没有变量是不可能的。”。将使用少量额外的内存。在这种情况下,程序中有一个额外的字符串也会增加内存,因为该字符串仍然存储在程序中。如果启用了优化,请忘记所有这些。这与主要问题无关,但我想我会提一下。你在玩弄pinvoke声明。如果代码在64位操作系统上运行,这肯定会损坏堆栈。它的副作用是非常随机的,与您描述的有关。您对
rtlmovemory
的p/invoke是错误的。您正在逐地址传递地址,这意味着它复制
pwk1
附近的内存,而不是
pwk1
指向的内存。请始终查看自动生成的代码。它肯定会出错…@Gendolkari,既然你让它工作了,就把你的结果写进一个答案,并把这个答案标记为正确。不要把你的问题当作没有答案而放弃。