问题描述
此代码会导致以下异常 :
This code causes the following exception, sometimes:
private static TOKEN_GROUPS GetTokenGroups(IntPtr tokenHandle)
{
var groups = new TOKEN_GROUPS();
uint tokenInfoLength = 0;
uint returnLength;
var res = GetTokenInformation(tokenHandle, TOKEN_INFORMATION_CLASS.TokenGroups, IntPtr.Zero,
tokenInfoLength, out returnLength);
if (!res && returnLength > 0)
{
tokenInfoLength = returnLength;
var tokenInfo = Marshal.AllocHGlobal((int) tokenInfoLength);
res = GetTokenInformation(tokenHandle,
TOKEN_INFORMATION_CLASS.TokenGroups,
tokenInfo,
tokenInfoLength,
out returnLength);
if(res)
{
groups = (TOKEN_GROUPS)Marshal.PtrToStructure(tokenInfo, typeof (TOKEN_GROUPS));
}
Marshal.FreeHGlobal(tokenInfo);
CloseHandle(tokenHandle);
}
else
{
var error = new Win32Exception(Marshal.GetLastWin32Error());
_log.WarnFormat("Failed evaluate the call to get process token information. {0}", error.Message);
}
return groups;
}
失败的行是 groups =(TOKEN_GROUPS) Marshal.PtrToStructure(tokenInfo,typeof(TOKEN_GROUPS));
我会说,异常发生在1和每20调用这个方法。一旦它开始发生每次调用之后将抛出异常。重新启动过程会导致错误消失。
The line that fails is groups = (TOKEN_GROUPS)Marshal.PtrToStructure(tokenInfo, typeof (TOKEN_GROUPS));
I would say the exception happens in 1 and every 20 calls to this method. Once it begins happening every call afterwards will throw the exception. Restarting the process causes the error to go away.
IntPtr tokenHandle
是以下结果:
var processId = GetCurrentProcess();
_log.InfoFormat("Process ID [{0}]", processId.ToString());
if (processId != IntPtr.Zero)
{
IntPtr tokenHandle;
if (OpenProcessToken(processId, TOKEN_READ, out tokenHandle))
{
groups = GetTokenGroups(tokenHandle);
}
EDIT 希望这不是信息过载,这里是pinvoke声明:
EDIT Hopefully this isn't information overload but here's the pinvoke declarations:
struct TOKEN_GROUPS
{
public uint GroupCount;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4000)]
public SID_AND_ATTRIBUTES[] Groups;
}
[StructLayout(LayoutKind.Sequential)]
struct SID_AND_ATTRIBUTES
{
public IntPtr SID;
public uint Attributes;
}
[DllImport("advapi32.dll", SetLastError = true)]
static extern bool GetTokenInformation(
IntPtr TokenHandle,
TOKEN_INFORMATION_CLASS TokenInformationClass,
IntPtr TokenInformation,
uint TokenInformationLength,
out uint ReturnLength);
[DllImport("advapi32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool OpenProcessToken(IntPtr ProcessHandle,
UInt32 DesiredAccess, out IntPtr TokenHandle);
[DllImport("kernel32.dll")]
static extern IntPtr GetCurrentProcess();
enum TOKEN_INFORMATION_CLASS
{
TokenUser = 1,
TokenGroups,
TokenPrivileges,
TokenOwner,
TokenPrimaryGroup,
TokenDefaultDacl,
TokenSource,
TokenType,
TokenImpersonationLevel,
TokenStatistics,
TokenRestrictedSids,
TokenSessionId,
TokenGroupsAndPrivileges,
TokenSessionReference,
TokenSandBoxInert,
TokenAuditPolicy,
TokenOrigin
}
推荐答案
我的猜测是,错误是没有正确释放资源的结果,正如你的情况。我可能是错误的原因,但它可能是一个好主意包装 FreeHGlobal
和 CloseHandle
My guess is that the error is a result of not correctly freeing up resources, as is the case in your situation. I may be wrong in it being the cause, but it's probably a good idea to wrap the FreeHGlobal
and CloseHandle
in a finally
block, to ensure proper cleaning up.
如果错误仍然存在,则可能是其他原因(错误的结构或或错误?)或错误使用此特定API(我不太熟悉)。
If the error then persists, it might be something else (wrong structure or wrong data layout in the declaration or wrong LayoutKind for TOKEN_GROUPS?) or wrong use of this particular API (which I'm not too familiar with).
问题可能在于必要的 SizeConst
属性参数。请考虑以下情况:GetTokenInformation已给出在tokeInfoLength中返回的大小。你分配这个。此大小不太可能等于 SizeConst
值。如果 SizeConst
大于所需大小,则 Marshal.PtrToStructure
将进一步访问您分配的长度,因为它只知道 SizeConst
,并且此内存可以访问,也可能不是。
The problem may very well lay in the necessary SizeConst
attribute parameter. Consider the following: the GetTokenInformation has given the size returned in tokeInfoLength. You allocate this. This size is not likely equal to the SizeConst
value. If SizeConst
is larger than the required size, the Marshal.PtrToStructure
will access further then the length that you allocated, because it knows only SizeConst
, and this memory may be accessible, and may be not.
要解决此问题,请确保 AllocHGlobal
调用至少是整个结构的大小作为编组。尝试,例如,添加4000,看看错误是否返回(其他,更整洁的解决方案存在,但让我们保持简单一会儿)。
To resolve this issue, make sure that the AllocHGlobal
call is at least the size of the whole structure as marshalled. Try, for instance, to add 4000 and see if the error returns (other, neater solutions exist, but let's keep it simple for a moment).
这篇关于管理到非托管代码调用导致访问冲突...有时的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!