如何将ProcessInfo转换为WTS_PROCESS_INFO

时间:2016-02-23 11:13:36

标签: c# c++ process pinvoke marshalling

我正在尝试调用WTSEnumerateProcesses(),但在将ProcessInfo类型转换为WTS_PROCESS_INFO时遇到了一些问题。

这是我到目前为止的代码:

ProcessInfo

    class ProcessInfo
    {
        public int basePriority;
        public int handleCount;
        public int mainModuleId;
        public long pageFileBytes;
        public long pageFileBytesPeak;
        public long poolNonpagedBytes;
        public long poolPagedBytes;
        public long privateBytes;
        public int processId;
        public string processName;
        public int sessionId;
        public ArrayList threadInfoList;
        public long virtualBytes;
        public long virtualBytesPeak;
        public long workingSet;
        public long workingSetPeak;

        public ProcessInfo()
        {

        }
    }

WTS_PROCESS_INFO

    public struct WTS_PROCESS_INFO
    {
        public int SessionID;
        public int ProcessID;
        // This is spointer to a string...
        public IntPtr ProcessName;
        public IntPtr userSid;
    }

WTSEnumerateProcesses()

    [DllImport("wtsapi32.dll", SetLastError = true)]
    static extern bool WTSEnumerateProcesses(
        IntPtr serverHandle, // Handle to a terminal server. 
        Int32 reserved,     // must be 0
        Int32 version,      // must be 1
        ref IntPtr ppProcessInfo, // pointer to array of WTS_PROCESS_INFO
        ref Int32 pCount     // pointer to number of processes
    );

    public static WTS_PROCESS_INFO[] WTSEnumerateProcesses()
    {
        IntPtr pProcessInfo = IntPtr.Zero;
        int processCount = 0;
        var hServer = OpenServer("XA7-06");

        if (!WTSEnumerateProcesses(hServer, 0, 1, ref pProcessInfo, ref processCount))
            return null;

        IntPtr pMemory = pProcessInfo;
        WTS_PROCESS_INFO[] processInfos = new WTS_PROCESS_INFO[processCount];
        for (int i = 0; i < processCount; i++)
        {
            processInfos[i] = (ProcessInfo)Marshal.PtrToStructure(pProcessInfo, typeof(WTS_PROCESS_INFO));
            pProcessInfo = (IntPtr)((int)pProcessInfo + Marshal.SizeOf(processInfos[i]));
        }

        WTSFreeMemory(pMemory);
        return processInfos;
    }

我的问题接近此行WTSEnumerateProcesses()方法的结尾:

processInfos[i] = (ProcessInfo)Marshal.PtrToStructure(pProcessInfo, typeof(WTS_PROCESS_INFO));

我认为我可能错过了定义WTS_PROCESS_INFOProcessInfo之间关系的步骤,但我不确定如何做到这一点。有人能指出我正确的方向吗?

这是我看到的错误:

// Cannot implicitly convert type 'ProcessInfo' to 'WTS_PROCESS_INFO'

1 个答案:

答案 0 :(得分:1)

您的ProcessInfo类型与WTS_PROCESS_INFO无关。所以这一行:

processInfos[i] = (ProcessInfo)Marshal.PtrToStructure(pProcessInfo, 
    typeof(WTS_PROCESS_INFO));

实际上包含两个错误。编译器拿起一个。具体而言,processInfos[i]属于WTS_PROCESS_INFO类型,并且与ProcessInfo不兼容。另一个错误是更微妙。您将Marshal.PtrToStructure()返回的值转换为类型ProcessInfo是错误的。 Marshal.PtrToStructure()返回的值为框WTS_PROCESS_INFO。所以代码行应该是:

processInfos[i] = (WTS_PROCESS_INFO)Marshal.PtrToStructure(pProcessInfo, 
    typeof(WTS_PROCESS_INFO));

您的指针算术在64位进程中可能会失败。如果您使用的是最新版本的.net,则可以直接在IntPtr上执行算术:

pProcessInfo += Marshal.SizeOf(processInfos[i]);

或者,如果您定位较旧的.net版本,则应通过强制转换为ulong而不是int来在64位上下文中执行算术。

至于你的ProcessInfo类型,我认为这只是你的错误思考。这里似乎没有用这种类型。

如果我是你,我会强制使用WTSEnumerateProcessesW的Unicode版本,例如:

[DllImport("wtsapi32.dll", EntryPoint = "WTSEnumerateProcessesW", SetLastError = true)]
static extern bool WTSEnumerateProcesses(
    ....
);

要将进程名称作为字符串读取,请将WTS_PROCESS_INFO结构中返回的指针传递给Marshal.PtrToStringUni