【问题标题】:C# struct behavior based on architecture基于架构的 C# struct 行为
【发布时间】:2016-05-18 06:09:44
【问题描述】:

我有一个关于根据编译架构将多个结构输入方法的问题, 或者关于正确布置 Thread_Basic_Information 结构,这样我就可以将单个结构用于相同的方法,而不管 x64/x86(参见参考:https://msdn.microsoft.com/en-us/library/windows/desktop/ms684283(v=vs.85).aspx

我已经确认它在 x86 上工作正常,如果我手动切换结构,它也适用于 x64。 然而,我最近尝试改变我的方法,从仅仅复制粘贴大量函数到尝试回收我的代码。

我很难找到有关结构的精确信息,我可以在 C# 中使用这些信息以使其兼容,无论 x86/x64 是什么,或者根据架构将 2 个不同的结构输入到相同的方法中.

也许是 StructLayout 包大小?但是我不熟悉该属性。

我希望有一种方法可以通用这个,例如如果 IntPtr.Size == 8 则使用 64 位结构,否则使用 32 位结构。不管复制粘贴代码的小重命名如何,我希望有一种方法可以使用泛型来做到这一点?

代码:

用于创建线程的方法:

public IRemoteThread Create(IntPtr address, bool isStarted = true)
{
    //Create the thread
    var thr = ThreadHelper.CreateRemoteThread(Process.Handle, address, IntPtr.Zero, ThreadCreationFlags.Suspended)
    //Acquire desired information from the thread
    var ret = ThreadHelper.NtQueryInformationThread(thr);

    // Do other stuff 
    return result;
}

支持查询我们想要的线程信息的方法:

public static ThreadBasicInformation NtQueryInformationThread(SafeMemoryHandle threadHandle)
{
    // Check if the handle is valid
    HandleManipulator.ValidateAsArgument(threadHandle, "threadHandle");

    // Create a structure to store thread info
    var info = new ThreadBasicInformation();

    // Get the thread info
    var ret = Nt.NtQueryInformationThread(threadHandle, 0, ref info, MarshalType<ThreadBasicInformation>.Size,
        IntPtr.Zero);

    // If the function succeeded
    if (ret == 0)
        return info;

    // Else, couldn't get the thread info, throws an exception
    throw new ApplicationException($"Couldn't get the information from the thread, error code '{ret}'.");
}

上述方法中使用的32位结构体:

[StructLayout(LayoutKind.Sequential)]
public struct ThreadBasicInformation
{
    public uint ExitStatus;

    public IntPtr TebBaseAdress;

    public int ProcessId;

    public int ThreadId;

    public uint AffinityMask;

    public uint Priority;

    public uint BasePriority;
}   

同一个结构的x64变体

[StructLayout(LayoutKind.Explicit)]
public struct ThreadBasicInformation64
{
    [FieldOffset(0)]
    public uint ExitStatus;

    [FieldOffset(8)]
    public IntPtr TebBaseAdress;

    [FieldOffset(16)]
    public int ProcessId;

    [FieldOffset(24)]
    public int ThreadId;

    [FieldOffset(32)]
    public uint AffinityMask;

    [FieldOffset(40)]
    public uint Priority;

    [FieldOffset(44)]
    public uint BasePriority;
}

编辑:

我找到的C声明:

typedef LONG KPRIORITY; 

typedef struct _CLIENT_ID { 
   HANDLE UniqueProcess; 
   HANDLE UniqueThread; 
} CLIENT_ID; 
typedef CLIENT_ID *PCLIENT_ID; 

typedef struct _THREAD_BASIC_INFORMATION 
{ 
   NTSTATUS                ExitStatus; 
   PVOID                   TebBaseAddress; 
   CLIENT_ID               ClientId; 
   KAFFINITY               AffinityMask; 
   KPRIORITY               Priority; 
   KPRIORITY               BasePriority; 
} THREAD_BASIC_INFORMATION, *PTHREAD_BASIC_INFORMATION; 

【问题讨论】:

  • 我不认为您需要不同的结构 32 和 64,而是系统。亲和力肯定是 IntPtr 。结构的 C 声明在哪里。
  • 提交了一个编辑,其中包含我在几个小时的搜索后发现的唯一有用的 C 声明。

标签: c# windows winapi struct


【解决方案1】:

您的问题的前提是错误的,因为您错误地翻译了结构。正确翻译它们后,您会发现可以在 C# 代码中使用结构的单个声明,编译器将为所有目标体系结构正确布局。

[StructLayout(LayoutKind.Sequential)]
public struct CLIENT_ID 
{
    public IntPtr UniqueProcess;
    public IntPtr UniqueThread;
}

[StructLayout(LayoutKind.Sequential)]
public struct THREAD_BASIC_INFORMATION
{
    public int ExitStatus;
    public IntPtr TebBaseAdress;
    public CLIENT_ID ClientId;
    public IntPtr AffinityMask;
    public int Priority;
    public int BasePriority;
}   

【讨论】:

  • 谢谢,您的帮助解决了我的问题。看来我可能需要加强我对 C/PP 的了解,然后再继续沿着这条道路走得更远,但无论如何我感谢您的帮助。
猜你喜欢
  • 2015-01-07
  • 2019-05-21
  • 2011-02-23
  • 1970-01-01
  • 2019-07-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-14
相关资源
最近更新 更多