vb.net - VB.Net 中的 UNC 空间
问题描述
我在这里(和其他地方)看到了很多帖子,这些帖子解决了在 UNC 路径上查找可用空间的问题,但这些都涉及使用 GetDiskFreeSpaceEx,它似乎只在 C 中可用。
我已经将它包含在一些测试代码中并得到:
Error BC30451 'GetDiskFreeSpaceEx' is not declared. It may be inaccessible due to its protection level.
IDE 提供了创建方法或属性的解决方案。
在控制台程序中尝试这个...
VB 相当于什么?
解决方案
使用 P/Invoke 时,我通常使用方法名称编写一个类,而不仅仅是方法声明本身,并尝试以 .NET 方式而不是低级 C++ 样式公开功能。
例如,在本机函数的方法描述中GetDiskFreeSpaceEx
提到,如果提供的路径是 UNC 路径,则后面的反斜杠是强制性的!
- C++风格:写在描述中,如果调用者没有以那种方式提供它,他们将自责,RTFM。
- .NET 风格:我们为调用者调整它,他们不必担心这样的实现细节。
我还将为每个可用信息提供 3 种不同的方法(我为使用的空间提供了第 4 种方法),以及一次获得多个值的常用方法。
它的外观如下:
Imports System
Imports System.ComponentModel
Imports System.IO
Imports System.Runtime.InteropServices
Namespace PInvoke.Kernel32
Public Class GetDiskFreeSpaceEx
''' <summary>
''' Retrieves the number of bytes currently available to the caller. This takes into account any quotas etc. that may
''' exist on the folder resp. file share.
''' </summary>
''' <param name="folderName">The name of the path to retrieve the for me available bytes from.</param>
''' <returns>The maximum number of bytes that are currently available for me to use.</returns>
Public Shared Function GetAvailableBytesToCaller(folderName As String) As UInt64
Dim result As SizeInfo = Invoke(folderName)
Return result.BytesAvailableToCaller
End Function
''' <summary>
''' Retrieves the number of bytes currently available on the according volume. This may be more than I can use,
''' see <see cref="GetAvailableBytesToCaller(String)" /> for a method that respects quotas etc.
''' </summary>
''' <param name="folderName">The name of the path to retrieve the (in general) available bytes from.</param>
''' <returns>The maximum number of bytes that are available for all users together.</returns>
Public Shared Function GetAvailableBytesInTotal(folderName As String) As UInt64
Dim result As SizeInfo = Invoke(folderName)
Return result.BytesAvailableInTotal
End Function
''' <summary>
''' Retrieves the number of bytes currently used on the according volume. This value corresponds to
''' <see cref="GetBytesInTotal(String)"/> - <see cref="GetAvailableBytesInTotal(String)"/>.
''' </summary>
''' <param name="folderName">The name of the path to retrieve the used bytes from.</param>
''' <returns>The number of bytes that are already used by all users together.</returns>
Public Shared Function GetUsedBytesInTotal(folderName As String) As UInt64
Dim result As SizeInfo = Invoke(folderName)
Return result.BytesUsedInTotal
End Function
''' <summary>
''' Retrieves the size in bytes of the according volume (the total of already used and available space).
''' </summary>
''' <param name="folderName">The name of the path to retrieve the (in general) available bytes from.</param>
''' <returns>The maximum number of bytes that are available for all users together.</returns>
Public Shared Function GetBytesInTotal(folderName As String) As UInt64
Dim result As SizeInfo = Invoke(folderName)
Return result.TotalNumberOfBytes
End Function
''' <summary>
''' Retrieves a <see cref="SizeInfo"/> object containing the information about how many bytes are available at
''' the given path in general or for the current user account, how much is the total and how much is already
''' used.
''' </summary>
''' <param name="folderName">The name of the path from which to retrieve the size info.</param>
''' <returns>The according size info object.</returns>
Public Shared Function Invoke(folderName As String) As SizeInfo
'Check argument
If (String.IsNullOrWhiteSpace(folderName)) Then
Throw New ArgumentNullException(NameOf(folderName), "The folder's name must not be null, empty or white-space!")
End If
'Expand environment variables
Try
folderName = Environment.ExpandEnvironmentVariables(folderName)
Catch ex As Exception
Throw New ArgumentException($"Unable to expand possible environment variables of folder '{folderName}'! See inner exception for details...", ex)
End Try
'Get full path
Try
folderName = Path.GetFullPath(folderName)
Catch ex As Exception
Throw New ArgumentException($"Unable to retrieve absolute path of folder '{folderName}'! See inner exception for details...", ex)
End Try
'Append final back-slash (which is mandatory for UNC paths)
folderName = folderName.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar)
If (Not folderName.EndsWith(Path.DirectorySeparatorChar)) Then
folderName &= Path.DirectorySeparatorChar
End If
'Invoke method
Dim bytesAvailableToCaller As UInt64
Dim bytesInTotal As UInt64
Dim bytesAvailableInGeneral As UInt64
Dim success As Boolean = Invoke(folderName, bytesAvailableToCaller, bytesInTotal, bytesAvailableInGeneral)
If (Not success) Then Throw New Win32Exception()
'Return result
Return New SizeInfo(bytesAvailableToCaller, bytesInTotal, bytesAvailableInGeneral)
End Function
'Private Methods
<DllImport("kernel32.dll", EntryPoint:="GetDiskFreeSpaceExW", ExactSpelling:=True, SetLastError:=True, CharSet:=CharSet.Unicode)>
Private Shared Function Invoke(folderName As String, ByRef bytesAvailableToCaller As UInt64, ByRef bytesInTotal As UInt64, ByRef bytesAvailableInGeneral As UInt64) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function
'************************************************************************************************************************
' Inner Class "SizeInfo"
'************************************************************************************************************************
Public Class SizeInfo
Public Sub New(freeBytesAvailableToCaller As UInt64, totalNumberOfBytes As UInt64, freeBytesAvailableInTotal As UInt64)
Me.BytesAvailableToCaller = freeBytesAvailableToCaller
Me.BytesAvailableInTotal = freeBytesAvailableInTotal
Me.TotalNumberOfBytes = totalNumberOfBytes
End Sub
Public ReadOnly Property BytesAvailableToCaller As UInt64
Public ReadOnly Property BytesAvailableInTotal As UInt64
Public ReadOnly Property BytesUsedInTotal As UInt64
Get
Dim total As UInt64 = TotalNumberOfBytes
Dim available As UInt64 = BytesAvailableInTotal
If (total <= available) Then Return 0
Return total - available
End Get
End Property
Public ReadOnly Property TotalNumberOfBytes As UInt64
End Class
End Class
End Namespace
推荐阅读
- yocto - eudev 被跳过:冲突的发行版功能“systemd”(在 DISTRO_FEATURES 中)
- node.js - 在 AWS lambda 中使用 nodejs 从 mongodb 中检索值
- unity3d - Unity中的贝塞尔曲线
- drupal - 如何在 Drupal 中使用 JSONAPI 请求否定过滤器?
- prometheus - 如何为普罗米修斯保留一些特殊的指标?
- ios - locationManager:didChangeAuthorization 与 locationManagerDidChangeAuthorization
- vba - MS Access 将可见的选定单元格移动到活动表活动行的第一个单元格
- .net - 我的 Obj-C GUI 应用程序如何打开我的 .Net Xamarin.IOS GUI 应用程序?
- java - EJB 计时器调度程序的 SQL 连续数据库阻塞
- python - 合并包含相似字符串的 CSV 文件中的行