如何使用超时实现类似于WNetAddConnection2的功能?

4
以下对 WNetAddConnection2 的调用似乎永远无法完成。请注意,机器名称是故意错误的 - 我希望它能快速失败而不是永久阻塞。有没有一种方法实现类似的功能但带有超时?
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Diagnostics;

namespace WindowsFormsApplication2
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        [StructLayout(LayoutKind.Sequential)]
        public class NETRESOURCE
        {
            public int dwScope;
            public int dwType;
            public int dwDisplayType;
            public int dwUsage;
            public string LocalName;
            public string RemoteName;
            public string Comment;
            public string Provider;
        }
        [DllImport("mpr.dll")]
        public static extern int WNetAddConnection2(NETRESOURCE netResource, string password, string username, int flags);

        private void Form1_Load(object sender, EventArgs e)
        {
            NETRESOURCE myResource = new NETRESOURCE();
            myResource.dwScope = 0;
            myResource.dwType = 0; //RESOURCETYPE_ANY
            myResource.dwDisplayType = 0;
            myResource.LocalName = "";
            myResource.RemoteName = @"\\invalid.machine.com";
            myResource.dwUsage = 0;
            myResource.Comment = "";
            myResource.Provider = "";

            int returnValue = WNetAddConnection2(myResource, "password", "username", 0); //hangs forever
            Debug.Print("Finished connecting");
        }
    }
}

2
永远是很长的时间。你等了多久?它应该最终超时。 - M.Babcock
几分钟 :) 我宁愿让我的线程等待几秒钟。 - Jon
将其放入线程并设置一个WaitHandle(如ManualResetEvent)以在WaitOne上设置超时,然后(采用粗暴的方式)使用Thread.Abort终止线程。 - M.Babcock
如果Thread.Abort与TerminateThread类似,那我宁愿避免使用它。http://msdn.microsoft.com/en-us/library/aa450930.aspx "TerminateThread是一个危险的函数。只在极端情况下使用它。" - Jon
@M.Babcock:Thread.Abort是不必要的,因为它无法中止连接尝试。 - Gabe
1个回答

3
在早期版本的Windows中,无法终止卡在WNetAddConnection函数中的进程。这个问题在Vista中得到了解决。根据Larry Osterman的说法,解决方法是使用CancelSynchronousIo函数。
解决方案如下:
1.启动一个新线程来运行WNetAddConnection2。
2.设置计时器或在现有线程中等待。
3.超时后,调用CancelSynchronousIo函数并指定连接线程的句柄。
我想不出任何原因会与.Net产生不良互动,但我还没有实际尝试过...

+1 个答案,但这引发了一个问题:“如何获取托管线程的本机线程句柄,当本机线程与托管线程没有固定关系时,是否应该这样做?” - Jon
在调用WNetAddConnection2之前,您可以使用pinvoke调用GetCurrentThreadId,但这并不是100%可靠的(在两个调用之间,您的托管线程可能会在不同的本机线程上重新安排)。您可以编写一个未管理的DLL,在新线程上启动WNetAddConnection并返回线程ID。虽然有点不太规范。 - arx
我尝试了这个,但是得到了ERROR_NOT_FOUND的错误,即使线程被阻塞在WNetAddConnection2上。根据http://msdn.microsoft.com/en-us/library/windows/desktop/aa363794%28v=vs.85%29.aspx的说明,“如果此函数无法找到要取消的请求,则返回值为0(零),并且GetLastError返回ERROR_NOT_FOUND。” - Jon
我也无法使其工作。我已经提了一个问题:http://stackoverflow.com/questions/9475581/does-cancelsynchronousio-work-with-wnetaddconnection2 - arx
1
@Jon:看起来我的建议有点失误:CancelSynchronousIo似乎无法与WNetAddConnection2一起使用。你可以使用一个单独的进程,这个进程可以被安全地终止。或者你可以将连接尝试保持在一个单独的线程中运行,并忘记它。 - arx
谢谢你的尝试。我希望能找到一个提供异步或者超时功能的替代 API,但我猜可能没有这样的。 - Jon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接