我正在构建将使用远程桌面服务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()。