SEHException при вызове WTSVirtualChannelClose

Я создаю приложение, которое будет взаимодействовать с сервером, используя API-интерфейс Remote Desktop Service.
Я создаю свое приложение с помощью кода, найденного здесь: 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) в Server.Server.Disconnect() в i:\Tomka\TS\v2\TSAddin\Server\Server.cs: строка 73

Я пытался получить последний Win32Error с помощью Marshal.GetLastWin32Error() но возвращается 1008,

Глядя в msdn, я нашел это описание ошибки:

ERROR_NO_TOKEN 1008 (0x3F0) Была сделана попытка сослаться на несуществующий токен.

Я нашел статью на MSDN, но код на C++, так что это не помогло, так или иначе, вот ссылка: http://msdn.microsoft.com/en-us/library/aa383852(v=vs.85).aspx

РЕДАКТИРОВАТЬ 1 Я сделал, как написал @Hans. Вот первое исключение, которое я получил:

Исключение первого шанса в 0x00000000771105B7 (ntdll.dll) в Server.exe: 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 я вызываю Server.Connect() и в FormClosed Server.Disconnect().

0 ответов

Другие вопросы по тегам