使用PowerShell在c#结构中设置值
我已将一些DHCP Win32 Api转换为C#,因此我可以使用PowerShell中的:使用PowerShell在c#结构中设置值,c#,powershell,pinvoke,C#,Powershell,Pinvoke,我已将一些DHCP Win32 Api转换为C#,因此我可以使用PowerShell中的: $definition = @" using System; using System.Collections.Generic; using System.Text; using System.Runtime.InteropServices; using System.Net; namespace Dhcpsapi { public enum DHCP_SEARCH_INFO_TYPE : i
$definition = @"
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Net;
namespace Dhcpsapi
{
public enum DHCP_SEARCH_INFO_TYPE : int
{
DhcpClientIpAddress = 0,
DhcpClientHardwareAddress = 1,
DhcpClientName = 2
};
[StructLayout(LayoutKind.Sequential)]
public struct DHCP_BINARY_DATA
{
public uint DataLength;
public IntPtr Data;
};
[StructLayout(LayoutKind.Sequential)]
public struct DHCP_IP_ADDRESS
{
public UInt32 IPAddress;
}
[StructLayout(LayoutKind.Explicit, Size=8)]
public struct SearchInfo
{
[FieldOffset(0)]
public DHCP_IP_ADDRESS ClientIpAddress;
[FieldOffset(0)]
public DHCP_BINARY_DATA ClientHardwareAddress;
[FieldOffset(0)]
public IntPtr ClientName; //LPWSTR
}
[StructLayout(LayoutKind.Sequential)]
public struct DHCP_SEARCH_INFO
{
public DHCP_SEARCH_INFO_TYPE SearchType;
public SearchInfo SearchInfo;
}
[StructLayout(LayoutKind.Sequential)]
public struct DATE_TIME
{
public UInt32 dwLowDateTime;
public UInt32 dwHighDateTime;
public DateTime ToDateTime()
{
if (dwHighDateTime == 0 && dwLowDateTime == 0)
{
return DateTime.MinValue;
}
if (dwHighDateTime == int.MaxValue && dwLowDateTime == UInt32.MaxValue)
{
return DateTime.MaxValue;
}
return DateTime.FromFileTime((((long)dwHighDateTime) << 32) | dwLowDateTime);
}
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct DHCP_HOST_INFO
{
public uint IpAddress;
public string NetBiosName;
public string HostName;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct DHCP_CLIENT_INFO
{
public uint ClientIpAddress;
public uint SubnetMask;
public DHCP_BINARY_DATA ClientHardwareAddress;
[MarshalAs(UnmanagedType.LPWStr)]
public string ClientName;
[MarshalAs(UnmanagedType.LPWStr)]
public string ClientComment;
public DATE_TIME ClientLeaseExpires;
public DHCP_HOST_INFO OwnerHost;
}
public static class PS
{
[DllImport("Dhcpsapi.dll")]
public static extern uint DhcpGetClientInfo(
[MarshalAs(UnmanagedType.LPWStr)]
string ServerIpAddress,
[MarshalAs(UnmanagedType.Struct)]
ref DHCP_SEARCH_INFO SearchInfo,
out IntPtr ClientInfo);
[DllImport("dhcpsapi.dll", SetLastError=true)]
public static extern void DhcpRpcFreeMemory(IntPtr BufferPointer);
}
}
"@
Add-Type -TypeDefinition $definition -PassThru
$dsi = New-Object dhcpsapi.DHCP_SEARCH_INFO
$dsi.SearchType = [Dhcpsapi.DHCP_SEARCH_INFO_TYPE]::DhcpClientIpAddress
$ipa = [System.Net.IPAddress]::Parse("10.4.3.101")
$ip = [UInt32][System.Net.IPAddress]::NetworkToHostOrder([int][System.BitConverter]::ToUInt32($ipa.GetAddressBytes(), 0))
# $ip is now 168035173
$dsi.SearchInfo.ClientIpAddress.IPAddress = $ip
#however $dsi.SearchInfo.ClientIpAddress.IPAddress is 0
$dsi.SearchInfo.ClientIpAddress.IPAddress
运行$dsi.SearchInfo.ClientIpAddress.IPAddress之后,它的值是0,而不是我预期的168035173。为什么会发生这种情况(它按照C#的预期工作)以及如何使其工作?SearchInfo是一个结构,因此当您执行此操作时:
#however $dsi.SearchInfo.ClientIpAddress.IPAddress is 0
$dsi.SearchInfo.ClientIpAddress.IPAddress
然后,您正在创建SearchInfo的副本,并且该副本上的值正在发生变化。对于每个结构,您需要对结构进行变异,然后重新分配:
$clientIpAddress = $dsi.SearchInfo.ClientIpAddress
$clientIpAddress.IPAddress = $ip
$searchInfo = $dsi.SearchInfo
$searchInfo.ClientIpAddress = $clientIpAddress
$dsi.SearchInfo = $searchInfo
问题是您使用的是结构,它是值类型,而不是引用类型。当通过PowerShell
“.
运算符访问这些成员时,它会返回该结构成员的副本,值赋值发生在该副本上,并且不会将其放入您试图修改的对象中
下面是一个较小的示例,演示了这一点:
> add-type @"
namespace TestStructs {
public struct Inner {
public int i;
};
public class Outer {
public Inner i;
}
}
"@
$s = new-object TestStructs.Outer
我创建了一个类Outer
,它有一个internal
结构作为成员I
。如果我尝试分配该值,则会得到您看到的行为,该行为保持为0:
> $s.i.i
0
> $s.i.i = 6
> $s.i.i
0
解决方法是分配整个结构。因此,对于这种简单的情况,我可以创建一个新结构,设置值,然后将其分配给我要修改的对象:
> $new_inner = new-object TestStructs.Inner
> $new_inner.i
0
> $new_inner.i = 6
> $new_inner.i
6
> $s.i = $new_inner
> $s.i.i
6
我可以用一些速记来做到这一点:
> $s.i = new-object TestStructs.Inner -prop @{ i = 7 }
> $s.i.i
7
但是,如果您的结构中有很多值,那么这可能不实用。因此,您还可以将其保存为临时值,然后重新指定:
> $s.i = &{ $temp = $s.i; $temp.i = 10; $temp }
H:\
> $s.i.i
10