windows 你能解释一下为什么 DirectoryInfo.GetFiles 会产生这个 IOException 吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/582988/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 12:02:40  来源:igfitidea点击:

Can you explain why DirectoryInfo.GetFiles produces this IOException?

.netwindowsnetworkingioexceptionnovell

提问by flipdoubt

I have a WinForms client-server app running on a Novell network that produces the following error when connecting to the lone Windows 2003 Server on the network:

我有一个在 Novell 网络上运行的 WinForms 客户端-服务器应用程序,它在连接到网络上单独的 Windows 2003 Server 时产生以下错误:

TYPE: System.IO.IOException
MSG: Logon failure: unknown user name or bad password.

SOURCE: mscorlib
SITE: WinIOError

  at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
  at System.IO.Directory.InternalGetFileDirectoryNames(String path,
    String userPathOriginal, String searchPattern, Boolean includeFiles, 
    Boolean includeDirs, SearchOption searchOption)
  at System.IO.DirectoryInfo.GetFiles(String searchPattern, 
    SearchOption searchOption)
  at System.IO.DirectoryInfo.GetFiles(String searchPattern)
  at Ceoimage.Basecamp.DocumentServers.ClientAccessServer.SendQueuedFiles(
    Int32 queueId, Int32 userId, IDocQueueFile[] queueFiles)
  at Ceoimage.Basecamp.ScanDocuments.DataModule.CommitDocumentToQueue(
    QueuedDocumentModelWithCollections doc, IDocQueueFile[] files)

The customer's network admin manages the Windows Server connection by manually synchronizing the workstation username and password with a local user on the server. The odd thing about the error is that the user can write to the server both before and after the error, all without explicitly logging on.

客户的网络管理员通过手动将工作站用户名和密码与服务器上的本地用户同步来管理 Windows Server 连接。该错误的奇怪之处在于,用户可以在错误发生之前和之后写入服务器,而无需显式登录。

Can you explain why the error occurs and offer a solution?

你能解释为什么会发生错误并提供解决方案吗?

回答by David

I have this same problem when trying to access the file system of a windows server in a different domain. The problem is that the user account that the program is running under does not have access to the remote server. Windows does extra work behind the scenes to make it look seamless when you use Windows Explorer because it guesses that your remote credentials will match your local credentials.

尝试访问不同域中的 Windows 服务器的文件系统时,我遇到了同样的问题。问题是运行程序的用户帐户无权访问远程服务器。当您使用 Windows 资源管理器时,Windows 在幕后做了额外的工作以使其看起来无缝,因为它猜测您的远程凭据将匹配您的本地凭据。

If you map a drive locally to the remote server, then use the locally mapped drive in your code, you shouldn't have the problem. If you can't map a drive, but you can hard code the credentials to use for the remote server, then you can use this code:

如果您将本地驱动器映射到远程服务器,然后在代码中使用本地映射驱动器,则应该不会出现问题。如果您无法映射驱动器,但可以硬编码用于远程服务器的凭据,则可以使用以下代码:

using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Security.Principal;

namespace Company.Security
{
    public class ImpersonateUser : IDisposable
    {
        [DllImport("advapi32.dll", SetLastError=true)]
        private static extern bool LogonUser(string lpszUsername, string lpszDomain, string lpszPassword, int dwLogonType, int dwLogonProvider, out IntPtr phToken);

        [DllImport( "kernel32", SetLastError = true )]
        private static extern bool CloseHandle(IntPtr hObject);

        private IntPtr userHandle = IntPtr.Zero;
        private WindowsImpersonationContext impersonationContext;

        public ImpersonateUser( string user, string domain, string password )
        {
            if ( ! string.IsNullOrEmpty( user ) )
            {
                // Call LogonUser to get a token for the user
                bool loggedOn = LogonUser( user, domain, password,
                    9 /*(int)LogonType.LOGON32_LOGON_NEW_CREDENTIALS*/,
                    3 /*(int)LogonProvider.LOGON32_PROVIDER_WINNT50*/,
                    out userHandle );
                if ( !loggedOn )
                    throw new Win32Exception( Marshal.GetLastWin32Error() );

                // Begin impersonating the user
                impersonationContext = WindowsIdentity.Impersonate( userHandle );
            }
        }

        public void Dispose()
        {
            if ( userHandle != IntPtr.Zero )
                CloseHandle( userHandle );
            if ( impersonationContext != null )
                impersonationContext.Undo();
        }
    }
}

Then you can access the remote server by doing this:

然后您可以通过执行以下操作访问远程服务器:

using ( new ImpersonateUser( "UserID", "Domain", "Password" ) )
{
    // Any IO code within this block will be able to access the remote server.
}

回答by Dennis Oosterkamp

For the VB.Net developers (like me) here's the VB.Net version:

对于 VB.Net 开发人员(像我一样),这里是 VB.Net 版本:

Imports System
Imports System.ComponentModel
Imports System.Runtime.InteropServices
Imports System.Security.Principal

Namespace Company.Security
    Public Class ImpersonateUser
        Implements IDisposable

        <DllImport("advapi32.dll", SetLastError:=True)> _
        Private Shared Function LogonUser(ByVal lpszUsername As String, ByVal lpszDomain As String, ByVal lpszPassword As String, ByVal dwLogonType As Integer, ByVal dwLogonProvider As Integer, ByRef phToken As IntPtr) As Integer
        End Function

        <DllImport("kernel32", SetLastError:=True)> _
        Private Shared Function CloseHandle(ByVal hObject As IntPtr) As Boolean
        End Function

        Private userHandle As IntPtr = IntPtr.Zero
        Private impersonationContext As WindowsImpersonationContext

        Public Sub New(ByVal user As String, ByVal domain As String, ByVal password As String)
            If Not String.IsNullOrEmpty(user) Then
                Dim loggedOn As Integer = LogonUser(user, domain, password, 9, 3, userHandle)
                If Not loggedOn = 1 Then
                    Throw New Win32Exception(Marshal.GetLastWin32Error())
                End If
                impersonationContext = WindowsIdentity.Impersonate(userHandle)
            End If
        End Sub

        Public Sub Dispose() Implements System.IDisposable.Dispose
            If userHandle <> IntPtr.Zero Then
                CloseHandle(userHandle)
            End If
            If impersonationContext IsNot Nothing Then
                impersonationContext.Undo()
            End If
        End Sub

    End Class
End Namespace

And use it like:

并像这样使用它:

using New ImpersonateUser( "UserID", "Domain", "Password" ) 
    ' ... your code here
End Using

回答by Davy Landman

I think you should try to reproduce the problem, and than use a packet monitor to see the network traffic and look at the difference between the failure situation and the success situation.

我认为您应该尝试重现问题,而不是使用数据包监视器查看网络流量并查看失败情况和成功情况之间的差异。

Then write a application which uses the raw api's from windows (P/Invokes) to reproduce your failure situation and try to find which parameters cause the error to occur. If your able to solve the problem than it's just the matter of finding how to get the components to do the thing you want.

然后编写一个应用程序,它使用 windows (P/Invokes) 中的原始 api 来重现您的失败情况,并尝试找出导致错误发生的参数。如果您能够解决问题,那么只需找到如何让组件完成您想要的事情即可。

Other directions you could look at (after you can stably reproduce the problem):

您可以查看的其他方向(在您可以稳定地重现问题之后):

  • Use Process Monitorto log all api calls and see where the error comes from.
  • Try it on a clean VM/Machine and try to reproduce it there
  • Disable the virus scanner
  • Update the novell client
  • 使用Process Monitor记录所有 api 调用并查看错误来自哪里。
  • 在干净的虚拟机/机器上尝试并尝试在那里重现它
  • 禁用病毒扫描程序
  • 更新小说客户端

回答by alexandrul

IMHO, it seems to be some kind of side effect of refreshing an expired authentication token (or something like that).

恕我直言,刷新过期的身份验证令牌(或类似的东西)似乎是某种副作用。

I my case, as an Active Directory user having internet access through a proxy (squid), I am browsing without problems until I get (at random intervals) an error about lack of credentials, which is solved by a page refresh in the browser, then everything is working fine until the next error.

我的情况是,作为通过代理 (squid) 访问 Internet 的 Active Directory 用户,我在浏览时没有问题,直到我(以随机间隔)收到有关缺少凭据的错误,这可以通过浏览器中的页面刷新来解决,然后一切正常,直到出现下一个错误。

回答by user2907498

There is a Microsoft example available at this address: https://msdn.microsoft.com/en-us/library/system.security.principal.windowsimpersonationcontext(v=vs.110).aspx

此地址有一个 Microsoft 示例:https: //msdn.microsoft.com/en-us/library/system.security.principal.windowsimpersonationcontext(v=vs.110).aspx

But it does say in their example: "On Windows Vista and later this sample must be run as an administrator."

但在他们的示例中确实说:“在 Windows Vista 和更高版本上,此示例必须以管理员身份运行。”

So this solution is good only if the user running the code is admin on most platforms.

因此,只有在大多数平台上运行代码的用户是管理员时,此解决方案才有效。