如何解决尝试枚举终端服务器会话会产生AccessViolationException.NET和本机DLL
我正在尝试使用WtsEnumerateSessionsExA
中定义的功能WtsApi32.dll
枚举C#中的所有远程桌面会话。
此函数将其指针作为参数传递的WTS_SESSION_INFO_1A
结构数组写入。您可以在此处找到文档:
我已经在C#中实现了WTS_SESSION_INFO_1A
结构和WTS_CONNECT_STATE_CLASS
,如下所示:
struct WtsSessionInfoClass
{
uint ExecEnvId;
WtsConnectStateClass state;
uint sessionId;
string pSessionName;
string pHostName;
string pUserName;
string pDomainName;
string pFarmName;
}
enum WtsConnectStateClass
{
WTSActive,WTSConnected,WTSConnectQuery,WTSShadow,WTSdisconnected,WTSIdle,WTSListen,WTSReset,WTSDown,WTSInit
}
我已经在名为Native32
的类中导入了所需的功能:
[DllImport("WtsApi32.dll")]
internal static extern IntPtr WTSOpenServerEx(string name);
[DllImport("WtsApi32.dll")]
internal static extern bool WTSEnumerateSessionsExA(
IntPtr hServer,UIntPtr pLevel,uint Filter,out WtsSessionInfoClass[] ppSessionInfo,UIntPtr pCount
);
最后,我的实现如下:
UIntPtr len = new UIntPtr();
WtsSessionInfoClass[] sessions;
IntPtr handle = Native32.WTSOpenServerEx("MyMachineName"); // This function gets the server handle and works fine
Native32.WTSEnumerateSessionsExA(handle,new UIntPtr(1),out sessions,len); // This function will produce AccessViolationException
...
执行代码时,由于Native32.WTSEnumerateSessionsExA
,对AccessViolationException
的调用失败。
我在这里做错了什么?任何帮助表示赞赏。
解决方法
我最好的猜测是您没有正确地传递第二个参数pLevel
。您正试图传递一个指向值为1的DWORD的指针,但实际上传递的是地址1。相反,声明一个初始化为1的局部变量,然后传递该地址。
更多详细信息:
您链接的WTSEnumerateSessionsExA的文档页面上说:
pLevel
此参数保留。始终将此参数设置为一个。在输出时, WTSEnumerateSessionsEx 不会更改此参数的值。
这里的措辞不是最好的,但是我的解释是您需要传递pLevel
的有效指针,并且该指针需要指向值为1的正确对齐的DWORD。
对我来说,另一种读法是您需要传递文字存储地址1作为pLevel
的指针。我本能地觉得这很荒谬。
但是,您的代码:
Native32.WTSEnumerateSessionsExA(
handle,new UIntPtr(1),out sessions,len);
传入new UIntPtr(1)
的{{1}}。根据我对UIntPtr doc pages的阅读,该表达式将创建一个指针,其字面值为1,即地址1。
如果您调试了WTSEnumerateSessionsEx实现的汇编代码,我的猜测是您会看到它尝试取消对pLevel
的引用,然后崩溃,并在尝试从地址加载DWORD时遇到访问冲突1。
要解决此问题,您可以声明一个包含值1的pLevel
变量,并将地址传递给该变量:
uint
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。