none
运算符“+”无法应用于“System.IntPtr”和“int”类型的操作数 RRS feed

  • 问题

  •  写一个程序需要调用windows的API,具体调用的类如下所示:

    /************************************* Module Header ***********************************\ 
    * Module Name:  CreateProcessAsUserWrapper.cs 
    * Project:      CSCreateProcessAsUserFromService 
    * Copyright (c) Microsoft Corporation. 
    *  
    * The sample demonstrates how to create/launch a process interactively in the session of  
    * the logged-on user from a service application written in C#.Net. 
    *  
    * This source is subject to the Microsoft Public License. 
    * See http://www.microsoft.com/en-us/openness/licenses.aspx#MPL 
    * All other rights reserved. 
    *  
    * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,  
    * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED  
    * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. 
    \***************************************************************************************/
    
    using System;
    using System.Runtime.InteropServices;
    
    namespace CSCreateProcessAsUserFromService
    {
        class CreateProcessAsUserWrapper
        {
            public static void LaunchChildProcess(string ChildProcName)
            {
                IntPtr ppSessionInfo = IntPtr.Zero;
                UInt32 SessionCount = 0;
    
                if (WTSEnumerateSessions(
                    (IntPtr)WTS_CURRENT_SERVER_HANDLE,  // Current RD Session Host Server handle would be zero. 
                    0,                                  // This reserved parameter must be zero. 
                    1,                                  // The version of the enumeration request must be 1. 
                    ref ppSessionInfo,                  // This would point to an array of session info. 
                    ref SessionCount                    // This would indicate the length of the above array. 
                    ))
                {
                    for (int nCount = 0; nCount < SessionCount; nCount++)
                    {
                        // Extract each session info and check if it is the  
                        // "Active Session" of the current logged-on user. 
                        WTS_SESSION_INFO tSessionInfo = (WTS_SESSION_INFO)Marshal.PtrToStructure(
                            ppSessionInfo + nCount * Marshal.SizeOf(typeof(WTS_SESSION_INFO)),
                            typeof(WTS_SESSION_INFO)
                            );
    
                        if (WTS_CONNECTSTATE_CLASS.WTSActive == tSessionInfo.State)
                        {
                            IntPtr hToken = IntPtr.Zero;
                            if (WTSQueryUserToken(tSessionInfo.SessionID, out hToken))
                            {
                                // Launch the child process interactively  
                                // with the token of the logged-on user. 
                                PROCESS_INFORMATION tProcessInfo;
                                STARTUPINFO tStartUpInfo = new STARTUPINFO();
                                tStartUpInfo.cb = Marshal.SizeOf(typeof(STARTUPINFO));
    
                                bool ChildProcStarted = CreateProcessAsUser(
                                    hToken,             // Token of the logged-on user. 
                                    ChildProcName,      // Name of the process to be started. 
                                    null,               // Any command line arguments to be passed. 
                                    IntPtr.Zero,        // Default Process' attributes. 
                                    IntPtr.Zero,        // Default Thread's attributes. 
                                    false,              // Does NOT inherit parent's handles. 
                                    0,                  // No any specific creation flag. 
                                    null,               // Default environment path. 
                                    null,               // Default current directory. 
                                    ref tStartUpInfo,   // Process Startup Info.  
                                    out tProcessInfo    // Process information to be returned. 
                                    );
    
                                if (ChildProcStarted)
                                {
                                    // The child process creation is successful! 
    
                                    // If the child process is created, it can be controlled via the out  
                                    // param "tProcessInfo". For now, as we don't want to do any thing  
                                    // with the child process, closing the child process' handles  
                                    // to prevent the handle leak. 
                                    CloseHandle(tProcessInfo.hThread);
                                    CloseHandle(tProcessInfo.hProcess);
                                }
                                else
                                {
                                    // CreateProcessAsUser failed! 
                                }
    
                                // Whether child process was created or not, close the token handle  
                                // and break the loop as processing for current active user has been done. 
                                CloseHandle(hToken);
                                break;
                            }
                            else
                            {
                                // WTSQueryUserToken failed! 
                            }
                        }
                        else
                        {
                            // This Session is not active! 
                        }
                    }
    
                    // Free the memory allocated for the session info array. 
                    WTSFreeMemory(ppSessionInfo);
                }
                else
                {
                    // WTSEnumerateSessions failed! 
                }
            }
    
    
            #region P/Invoke WTS APIs
            /// <summary> 
            /// Struct, Enum and P/Invoke Declarations of WTS APIs. 
            /// </summary> 
            ///  
    
            private const int WTS_CURRENT_SERVER_HANDLE = 0;
            private enum WTS_CONNECTSTATE_CLASS
            {
                WTSActive,
                WTSConnected,
                WTSConnectQuery,
                WTSShadow,
                WTSDisconnected,
                WTSIdle,
                WTSListen,
                WTSReset,
                WTSDown,
                WTSInit
            }
    
            [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
            private struct WTS_SESSION_INFO
            {
                public UInt32 SessionID;
                public string pWinStationName;
                public WTS_CONNECTSTATE_CLASS State;
            }
    
            [DllImport("WTSAPI32.DLL", SetLastError = true, CharSet = CharSet.Auto)]
            static extern bool WTSEnumerateSessions(
                IntPtr hServer,
                [MarshalAs(UnmanagedType.U4)] UInt32 Reserved,
                [MarshalAs(UnmanagedType.U4)] UInt32 Version,
                ref IntPtr ppSessionInfo,
                [MarshalAs(UnmanagedType.U4)] ref UInt32 pSessionInfoCount
                );
    
            [DllImport("WTSAPI32.DLL", SetLastError = true, CharSet = CharSet.Auto)]
            static extern void WTSFreeMemory(IntPtr pMemory);
    
            [DllImport("WTSAPI32.DLL", SetLastError = true, CharSet = CharSet.Auto)]
            static extern bool WTSQueryUserToken(UInt32 sessionId, out IntPtr Token);
            #endregion
    
    
            #region P/Invoke CreateProcessAsUser
            /// <summary> 
            /// Struct, Enum and P/Invoke Declarations for CreateProcessAsUser. 
            /// </summary> 
            ///  
    
            [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
            struct STARTUPINFO
            {
                public Int32 cb;
                public string lpReserved;
                public string lpDesktop;
                public string lpTitle;
                public Int32 dwX;
                public Int32 dwY;
                public Int32 dwXSize;
                public Int32 dwYSize;
                public Int32 dwXCountChars;
                public Int32 dwYCountChars;
                public Int32 dwFillAttribute;
                public Int32 dwFlags;
                public Int16 wShowWindow;
                public Int16 cbReserved2;
                public IntPtr lpReserved2;
                public IntPtr hStdInput;
                public IntPtr hStdOutput;
                public IntPtr hStdError;
            }
    
            [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
            struct PROCESS_INFORMATION
            {
                public IntPtr hProcess;
                public IntPtr hThread;
                public int dwProcessId;
                public int dwThreadId;
            }
    
            [DllImport("ADVAPI32.DLL", SetLastError = true, CharSet = CharSet.Auto)]
            static extern bool CreateProcessAsUser(
                IntPtr hToken,
                string lpApplicationName,
                string lpCommandLine,
                IntPtr lpProcessAttributes,
                IntPtr lpThreadAttributes,
                bool bInheritHandles,
                uint dwCreationFlags,
                string lpEnvironment,
                string lpCurrentDirectory,
                ref STARTUPINFO lpStartupInfo,
                out PROCESS_INFORMATION lpProcessInformation
                );
    
            [DllImport("KERNEL32.DLL", SetLastError = true, CharSet = CharSet.Auto)]
            static extern bool CloseHandle(IntPtr hHandle);
            #endregion
        }
    }

    用Framework4.0可以编译通过,但是用2.0的话一旦编译就报如下错误:

    运算符“+”无法应用于“System.IntPtr”和“int”类型的操作数,如果必须在2.0下进行编译,请问这个问题该怎么解决呀?

    2012年12月19日 7:29

答案

  • 你好,

    这是因为在4.0中IntPtr定义了 + 的作用。当你把鼠标放在 + 上时,你可以看到它的描述是 给这个指针加上一个offset。而2.0的版本里没有这样做。

    从p = p + 100的IL代码来看, 它调用了一个非公开的加的方法,而这个加的方法的实现过程是将这个intPtr转换成Int32然后加上那个int32数字,然后再调用Intptr的构造方法返回一个Intptr,所以在2.0,你可以自己写这个过程。


    Mike Feng
    MSDN Community Support | Feedback to us
    Develop and promote your apps in Windows Store
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    2012年12月20日 3:22
    版主
  • [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
    internal static IntPtr IntPtrOffset(IntPtr pbase, int offset)
    {
      if (4 == IntPtr.Size)
      {
        return (IntPtr) (pbase.ToInt32() + offset);
      }
      return (IntPtr) (pbase.ToInt64() + offset);
    }

    自己写吧,4.0做了操作符重载。
    2012年12月20日 6:36

全部回复

  • 你好,

    这是因为在4.0中IntPtr定义了 + 的作用。当你把鼠标放在 + 上时,你可以看到它的描述是 给这个指针加上一个offset。而2.0的版本里没有这样做。

    从p = p + 100的IL代码来看, 它调用了一个非公开的加的方法,而这个加的方法的实现过程是将这个intPtr转换成Int32然后加上那个int32数字,然后再调用Intptr的构造方法返回一个Intptr,所以在2.0,你可以自己写这个过程。


    Mike Feng
    MSDN Community Support | Feedback to us
    Develop and promote your apps in Windows Store
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    2012年12月20日 3:22
    版主
  • [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
    internal static IntPtr IntPtrOffset(IntPtr pbase, int offset)
    {
      if (4 == IntPtr.Size)
      {
        return (IntPtr) (pbase.ToInt32() + offset);
      }
      return (IntPtr) (pbase.ToInt64() + offset);
    }

    自己写吧,4.0做了操作符重载。
    2012年12月20日 6:36
  • 好的,谢了哈
    2012年12月21日 13:19