调用WTSVirtualChannelClose时出现SEHException

时间:2014-10-27 11:11:22

标签: c# winapi pinvoke rdp virtual-channel

我正在构建将使用远程桌面服务API与服务器通信的应用程序 我正在使用以下代码构建我的应用程序:https://code.google.com/p/tstunnels/和此处:http://www.codeproject.com/Articles/16374/How-to-Write-a-Terminal-Services-Add-in-in-Pure-C
我构建了当我进行远程桌面连接时加载的客户端库,我能够发送和接收消息。

在服务器端,当我试图关闭我的应用程序时,我收到SEHException。

我使用DLLImport使用此方法:

[DllImport("Wtsapi32.dll", SetLastError = true)]
public static extern IntPtr WTSVirtualChannelOpen(IntPtr server, int sessionId, [MarshalAs(UnmanagedType.LPStr)] string virtualName);

[DllImport("Wtsapi32.dll", SetLastError = true)]
public static extern bool WTSVirtualChannelQuery(IntPtr channelHandle, WtsVirtualClass Class, out IntPtr data, out int bytesReturned);

[DllImport("Wtsapi32.dll")]
public static extern void WTSFreeMemory(IntPtr memory);

[DllImport("Wtsapi32.dll", SetLastError = true)]
public static extern bool WTSVirtualChannelWrite(IntPtr channelHandle, byte[] data, int length, out int bytesWritten);

[DllImport("Wtsapi32.dll")]
public static extern bool WTSVirtualChannelClose(IntPtr channelHandle);

public static Stream WTSVirtualChannelQuery_WTSVirtualFileHandle(IntPtr channelHandle)
{
    int len;
    IntPtr buffer;
    var b = WTSVirtualChannelQuery(channelHandle, WtsVirtualClass.WTSVirtualFileHandle, out buffer, out len);
    if (!b) throw new Win32Exception();
    var fileHandle = new SafeFileHandle(Marshal.ReadIntPtr(buffer), true);
    WTSFreeMemory(buffer);

    return new FileStream(fileHandle, FileAccess.ReadWrite, 0x1000, true);
}

然后在我的应用程序中我正在这样做:

mHandle = Native.WTSVirtualChannelOpen(IntPtr.Zero, -1, ChannelName);
if (mHandle == IntPtr.Zero)
{
    Log("RDP Virtual channel Open Failed: " + new Win32Exception().Message);
    return;
}

try
{
    var stream = Native.WTSVirtualChannelQuery_WTSVirtualFileHandle(mHandle);
    reader = new BinaryReader(new BufferedStream(stream));
}
catch (Win32Exception ex)
{
    Log("RDP Virtual channel Query Failed: " + ex.Message);
    return;
}

之后我可以通过虚拟频道进行写入和读取,但是当我尝试使用下面的代码关闭时,我会收到错误。

if (reader != null) reader.Close();
var ret = Native.WTSVirtualChannelClose(mHandle);

这是错误:

  

System.Runtime.InteropServices.SEHException(0x80004005):外部   组件抛出异常。在   Server.Native.WTSVirtualChannelClose(IntPtr channelHandle)at   Server.Server.Disconnect()中   i:\ Tomka \ TS \ v2 \ TSAddin \ Server \ Server.cs:第73行

我尝试使用Marshal.GetLastWin32Error()获取最后一个Win32Error,但它返回1008

查看msdn我发现了错误说明:

  

ERROR_NO_TOKEN 1008(0x3F0)尝试引用令牌   那不存在。

我在MSDN上找到了文章,但代码是用C ++编写的,所以没有帮助,无论如何这里是链接:http://msdn.microsoft.com/en-us/library/aa383852(v=vs.85).aspx

编辑1 我做了@Hans写道。 这是我得到的第一个例外:

  

Server.exe中0x00000000771105B7(ntdll.dll)的第一次机会异常:   0xC0000008:指定了无效句柄。

编辑2

以下是我在服务器上使用的类:

class Native
{
    [DllImport("Wtsapi32.dll", SetLastError = true)]
    public static extern IntPtr WTSVirtualChannelOpen(IntPtr server, int sessionId, [MarshalAs(UnmanagedType.LPStr)] string virtualName);

    [DllImport("Wtsapi32.dll", SetLastError = true)]
    public static extern bool WTSVirtualChannelQuery(IntPtr channelHandle, WtsVirtualClass Class, out IntPtr data, out int bytesReturned);

    [DllImport("Wtsapi32.dll")]
    public static extern void WTSFreeMemory(IntPtr memory);

    [DllImport("Wtsapi32.dll", SetLastError = true)]
    public static extern bool WTSVirtualChannelWrite(IntPtr channelHandle, byte[] data, int length, out int bytesWritten);

    [DllImport("Wtsapi32.dll", SetLastError = true)]
    public static extern bool WTSVirtualChannelRead(IntPtr channelHandle, int timeOut, IntPtr data, int length, out int bytesRead);

    [DllImport("Wtsapi32.dll")]
    public static extern bool WTSVirtualChannelClose(IntPtr channelHandle);

    public static Stream WTSVirtualChannelQuery_WTSVirtualFileHandle(IntPtr channelHandle)
    {
        int len;
        IntPtr buffer;
        var b = WTSVirtualChannelQuery(channelHandle, WtsVirtualClass.WTSVirtualFileHandle, out buffer, out len);
        if (!b) throw new Win32Exception();
        var fileHandle = new SafeFileHandle(Marshal.ReadIntPtr(buffer), true);
        WTSFreeMemory(buffer);
        return new FileStream(fileHandle, FileAccess.ReadWrite, 0x1000, true);
    }

    public enum WtsVirtualClass
    {
        WTSVirtualClient = 0,
        WTSVirtualFileHandle = 1
    }
}

和Server.cs:

public class Server
{
    private IntPtr mHandle;
    private BinaryReader reader;

    public bool IsConnected { get; private set; }
    private bool SeenHello;

    public const string ChannelName = "TEST";


    private delegate void Action();
    public void Connect()
    {
        mHandle = Native.WTSVirtualChannelOpen(IntPtr.Zero, -1, ChannelName);
        if (mHandle == IntPtr.Zero)
        {
            Log("RDP Virtual channel Open Failed: " + new Win32Exception().Message);
            return;
        }

        try
        {
            var stream = Native.WTSVirtualChannelQuery_WTSVirtualFileHandle(mHandle);
            reader = new BinaryReader(new BufferedStream(stream));
        }
        catch (Win32Exception ex)
        {
            Log("RDP Virtual channel Query Failed: " + ex.Message);
            return;
        }

        IsConnected = true;
        Log("Connected");

        Action process = Process;
        process.BeginInvoke(process.EndInvoke, null);

        Action hello = () =>
        {
            while (!SeenHello && IsConnected)
            {
                WriteMessage("HELLO");
                Log("Sending HELLO");
                Thread.Sleep(200);
            }
        };
        hello.BeginInvoke(hello.EndInvoke, null);
    }

    public void Disconnect()
    {
        IsConnected = false;
        if (reader != null) reader.Close();
        var ret = Native.WTSVirtualChannelClose(mHandle);
    }

    private void Process()
    {
        while (IsConnected)
        {
            try
            {
                var len = reader.ReadInt32();
                Log(len.ToString());
                byte[] buff = reader.ReadBytes(len);

                Log(Encoding.UTF8.GetString(buff));
                MessageReceived(Encoding.UTF8.GetString(buff));
            }
            catch (OperationCanceledException ex)
            {
                Log(ex);
                return;
            }
            catch (Exception ex)
            {
                Log(ex);
            }
        }
    }

    public bool WriteMessage(string msg)
    {
        byte[] data = Encoding.UTF8.GetBytes(msg);
        int written;
        var ret = Native.WTSVirtualChannelWrite(mHandle, data, data.Length, out written);
        if (ret) return true;
        var ex = new Win32Exception();
        if (!SeenHello && ex.NativeErrorCode == 1 /* Incorrect Function */) return false;
        Log("RDP Virtual channel Write Failed: " + ex.Message);
        return false;
    }

    public void MessageReceived(string msg)
    {
        Log(msg);
        if (msg.ToUpper() == "HELLO:RESPONSE")
        {
            if (!SeenHello)
            {
                SeenHello = true;
                OnConnected(msg);
            }
        }

        OnMessage(msg);
    }

    public EventHandler<MessageEventArgs> Connected;

    protected void OnConnected(string msg)
    {
        if (Connected != null)
            Connected(this, new MessageEventArgs(msg));
    }

    public EventHandler<MessageEventArgs> Message;

    protected void OnMessage(string msg)
    {
        if (Message != null)
            Message(this, new MessageEventArgs(msg));
    }


    public void Log(object message)
    {
        OnMessageLogged(message.ToString());
    }

    public EventHandler<MessageEventArgs> MessageLogged;

    protected void OnMessageLogged(string message)
    {
        if (MessageLogged != null)
            MessageLogged(this, new MessageEventArgs(message));
    }
}

用法如下:

在主窗体构造函数中,我正在创建服务器对象,在Load I中调用Server.Connect()和FormClosed Server.Disconnect()。

0 个答案:

没有答案