我使用Win32 API进行DHCP操作,并按照pinvoke.com的代码示例,我发现当我冒充用户时示例代码会杀死我的应用,并且当我模仿时工作正常不是。我相信它与Marshal.FreeCoTaskMem和/或Marshal.DestroyStructure有关,但我不明白为什么。
我有点害怕内存泄漏,所以我想这样做。由于我潜入了非托管的世界,我的理解是需要手动清理内存,因此调用Marshal.FreeCoTaskMem或Marshal.DestroyStructure。如果我没有在封闭的Impersonation使用块中调用它,这些方法可以正常工作。否则(通过设置断点)我看到只要GetDHCPServers()方法击中上述死亡点,就会触及Impersonation类的Dispose方法。
我的问题是 - 考虑到我是如何冒充的,我是否需要担心使用Marshal来清理自己,或者是否多余?如果我需要做某事,那么在没有爆炸封闭的模拟课程的情况下,这样做的安全方法是什么?
以下是我冒充的方式:
[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
public class Impersonation : IDisposable
{
private readonly SafeTokenHandle _handle;
private readonly WindowsImpersonationContext _context;
const int LOGON32_LOGON_NEW_CREDENTIALS = 9;
// WIN32 API
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
private static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword, int dwLogonType, int dwLogonProvider, out SafeTokenHandle phToken);
public Impersonation(string domain, string username, string password)
{
var ok = LogonUser(username, domain, password,LOGON32_LOGON_NEW_CREDENTIALS, 0, out this._handle);
if (!ok)
{
var errorCode = Marshal.GetLastWin32Error();
throw new ApplicationException(string.Format("Could not impersonate the elevated user. LogonUser returned error code {0}.", errorCode));
}
this._context = WindowsIdentity.Impersonate(this._handle.DangerousGetHandle());
}
public void Dispose()
{
this._context.Dispose();
this._handle.Dispose();
}
}
然后我在启动DHCP服务器查找器时使用此模拟上下文,如下所示:
using (new Impersonation(_domain, _user, _password))
{
DHCPScanner.GetDHCPServers();
}
这是问题发生的地方,单元测试只是失败(没有例外,它只是停止运行):
[DllImport("dhcpsapi.dll", SetLastError = true, CharSet = CharSet.Unicode)]
private static extern uint DhcpEnumSubnets(
string ServerIpAddress,
ref uint ResumeHandle,
uint PreferredMaximum,
out IntPtr EnumInfo,
ref uint ElementsRead,
ref uint ElementsTotal
);
public static void GetDHCPServers()
{
IntPtr svrs;
uint dhcpResult = DhcpEnumServers(0, IntPtr.Zero, out svrs, IntPtr.Zero, IntPtr.Zero);
if (dhcpResult == 0)
{
DHCP_SERVER_INFO_ARRAY dsArray = (DHCP_SERVER_INFO_ARRAY)Marshal.PtrToStructure(svrs, typeof(DHCP_SERVER_INFO_ARRAY));
int size = (int)dsArray.NumElements;
IntPtr outArray = dsArray.Servers;
DHCPDS_SERVER[] serverList = new DHCPDS_SERVER[size];
DHCP_SERVERS[] outlist = new DHCP_SERVERS[size];
IntPtr current = outArray;
for (int i = 0; i < size; i++)
{
serverList[i] = new DHCPDS_SERVER();
Marshal.PtrToStructure(current, serverList[i]);
// the below line kills the process if I uncomment it
//Marshal.DestroyStructure(current, typeof(DHCPDS_SERVER));
current = (IntPtr)((int)current + Marshal.SizeOf(serverList[i]));
outlist[i].ServerName = serverList[i].ServerName;
outlist[i].ServerAddress = UInt32IPAddressToString(serverList[i].ServerAddress);
}
Marshal.FreeCoTaskMem(outArray); // <-- dies here too
}
}