我对.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将包含指向用户名和logon_domain的指针。
如果我将其更改为Dim login As String,则它包含一个仅指向用户名的指针。根据我将(完全未使用的)变量名更改为什么,我会得到不同的结果。这怎麽可能?
我一直有这样的印象:变量的名称与您选择的名称无关紧要。声明一个变量,然后再也不使用它,这和根本没有变量是不可能的。
我已经在两台电脑上试过了,结果一致(一台在.Net 3.5上,一台在4.0上)。然而,当我尝试将其转换为C#时,我无法重现它。
顺便说一句,我知道我可以使用System.Environment来获取我所需要的关于当前用户信息的信息;这是自动升级的旧VB6代码(我对它进行了一些编辑,使它变得更简单)。我只是在试着理解这种行为是如何发生的。显然,我花了很多年时间对.Net做了一些不太真实的假设。
发布于 2012-05-23 01:07:09
在Raymond Chen的帮助下,解决方案:
RtlMoveMemory的声明应该将src作为ByVal传递,而不是作为ByRef。因为我传递的src是一个指向内存位置的指针,所以传递给它ByRef会导致它传递存储指针的内存地址……换句话说,我的变量声明的位置。因此,使用其他变量或不同名称的变量会产生不同的结果。
关于为什么它会被传递给ByRef的说明...在原始的VB6代码中,它没有在声明中指定ByVal,而ByRef是VB6中的默认值。因此,声明本身是预期的ByRef。但是,对该应用程序接口的调用指定它正在传递变量ByVal。这是在.Net中不能做的事情;您必须像声明所期望的那样传递它。因此,自动升级器将ByRef添加到声明中,这确实使声明与VB6相同,但它忽略了调用中的ByVal。
https://stackoverflow.com/questions/10035157
复制相似问题