WPF 使用 WNetUseConnection 連接 SMB 網(wǎng)絡(luò)資源
為了方便起見(jiàn),我編寫(xiě)了一個(gè)簡(jiǎn)單的界面,代碼如下
<Grid>
<StackPanel VerticalAlignment="Center">
<Grid MinWidth="300" HorizontalAlignment="Center">
<Grid.Resources>
<Style TargetType="TextBlock">
<Setter Property="Margin" Value="0 5 5 5"></Setter>
</Style>
<Style TargetType="TextBox">
<Setter Property="Margin" Value="0 5 0 5"></Setter>
</Style>
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Text="Url:"></TextBlock>
<TextBox x:Name="UrlTextBox" Grid.Row="0" Grid.Column="1" Text="\\nas.lindexi.com\Data\"></TextBox>
<TextBlock Grid.Row="1" Grid.Column="0" Text="賬號(hào):"></TextBlock>
<TextBox x:Name="UserNameTextBox" Grid.Row="1" Grid.Column="1"></TextBox>
<TextBlock Grid.Row="2" Grid.Column="0" Text="密碼:"></TextBlock>
<TextBox x:Name="PasswordTextBox" Grid.Row="2" Grid.Column="1"></TextBox>
</Grid>
<Button x:Name="ConnectButton" Width="100" Height="30" Margin="10" Click="ConnectButton_OnClick">連接</Button>
</StackPanel>
</Grid>
運(yùn)行起來(lái)的界面大概如下

點(diǎn)擊連接按鈕時(shí),將嘗試連接以上配置的各項(xiàng)內(nèi)容
如上圖所示,我將嘗試連接到我的 SMB 上。對(duì)于 Windows 來(lái)說(shuō),以上的 \\nas.lindexi.com\Data\ 就是一個(gè)非常合法的路徑,連接完成之后,即可直接訪(fǎng)問(wèn)
本文的重點(diǎn)是調(diào)用 WNetUseConnection 方法進(jìn)行連接,此方法的官方說(shuō)明文檔是 WNetUseConnectionW 函數(shù) (winnetwk.h) - Win32 apps - Microsoft Learn
其 PInvoke 定義代碼如下
[DllImport("Mpr.dll")]
private static extern int WNetUseConnection
(
IntPtr hwndOwner,
NETRESOURCE lpNetResource,
string lpPassword,
string lpUserID,
int dwFlags,
string? lpAccessName,
string? lpBufferSize,
string? lpResult
);
結(jié)構(gòu)體 NETRESOURCE 的定義如下
[StructLayout(LayoutKind.Sequential)]
private struct NETRESOURCE()
{
public int dwScope = 0;
public int dwType = 0;
public int dwDisplayType = 0;
public int dwUsage = 0;
public string lpLocalName = "";
public string lpRemoteName = "";
public string lpComment = "";
public string lpProvider = "";
}
為了方便調(diào)用,我編寫(xiě)了 NetworkShare 輔助類(lèi),代碼如下
public static class NetworkShare
{
public static int ConnectToShare(string uri, string username, string password)
{
//Create netresource and point it at the share
NETRESOURCE netResource = new NETRESOURCE();
netResource.dwType = RESOURCETYPE_DISK;
netResource.lpRemoteName = uri;
int result = WNetUseConnection(IntPtr.Zero, netResource, password, username, 0, null, null, null);
return result;
}
const int RESOURCETYPE_DISK = 0x00000001;
const int CONNECT_UPDATE_PROFILE = 0x00000001;
...
}
對(duì)于 Win32 調(diào)用來(lái)說(shuō),一般都有成對(duì)的釋放代碼,這里使用的是 WNetCancelConnection 進(jìn)行斷開(kāi)
同樣做簡(jiǎn)單的封裝
public static class NetworkShare
{
public static int DisconnectFromShare(string uri, bool force)
{
int result = WNetCancelConnection(uri, force);
return result;
}
[DllImport("Mpr.dll")]
private static extern int WNetCancelConnection
(
string lpName,
bool fForce
);
...
}
整個(gè) NetworkShare 的代碼如下
public static class NetworkShare
{
public static int ConnectToShare(string uri, string username, string password)
{
//Create netresource and point it at the share
NETRESOURCE netResource = new NETRESOURCE();
netResource.dwType = RESOURCETYPE_DISK;
netResource.lpRemoteName = uri;
int result = WNetUseConnection(IntPtr.Zero, netResource, password, username, 0, null, null, null);
return result;
}
public static int DisconnectFromShare(string uri, bool force)
{
int result = WNetCancelConnection(uri, force);
return result;
}
const int RESOURCETYPE_DISK = 0x00000001;
const int CONNECT_UPDATE_PROFILE = 0x00000001;
[StructLayout(LayoutKind.Sequential)]
private struct NETRESOURCE()
{
public int dwScope = 0;
public int dwType = 0;
public int dwDisplayType = 0;
public int dwUsage = 0;
public string lpLocalName = "";
public string lpRemoteName = "";
public string lpComment = "";
public string lpProvider = "";
}
[DllImport("Mpr.dll")]
private static extern int WNetUseConnection
(
IntPtr hwndOwner,
NETRESOURCE lpNetResource,
string lpPassword,
string lpUserID,
int dwFlags,
string? lpAccessName,
string? lpBufferSize,
string? lpResult
);
[DllImport("Mpr.dll")]
private static extern int WNetCancelConnection
(
string lpName,
bool fForce
);
}
完成之后的調(diào)用代碼如下
private void ConnectButton_OnClick(object sender, RoutedEventArgs e)
{
var success = NetworkShare.ConnectToShare(UrlTextBox.Text, UserNameTextBox.Text, PasswordTextBox.Text);
if (success == 0)
{
foreach (var fileSystemEntry in Directory.EnumerateFileSystemEntries(UrlTextBox.Text))
{
Debug.WriteLine(fileSystemEntry);
}
NetworkShare.DisconnectFromShare(UrlTextBox.Text, force: true);
}
}
當(dāng)輸入的地址和賬號(hào)密碼正確時(shí),預(yù)期可以在 ConnectButton_OnClick 里面枚舉出當(dāng)前 SMB 網(wǎng)絡(luò)資源的各項(xiàng)文件夾和文件
我為了方便自己調(diào)試,我還引入了 https://github.com/dotnet-campus/dotnetCampus.Configurations 硬幣配置文件庫(kù),將連接地址和賬號(hào)密碼存放在 COIN 硬幣配置文件里,其代碼如下
public MainWindow()
{
InitializeComponent();
var coinFile = @"C:\lindexi\Nas.coin";
if (File.Exists(coinFile))
{
var fileConfigurationRepo = ConfigurationFactory.FromFile(coinFile,RepoSyncingBehavior.Static);
var appConfigurator = fileConfigurationRepo.CreateAppConfigurator();
var nasConfiguration = appConfigurator.Of<NasConfiguration>();
UrlTextBox.Text = nasConfiguration.Url;
UserNameTextBox.Text = nasConfiguration.UserName;
PasswordTextBox.Text = nasConfiguration.Password;
}
}
class NasConfiguration : Configuration
{
public NasConfiguration() : base("")
{
}
public string Url => GetString();
public string UserName => GetString();
public string Password => GetString();
}
本文代碼放在 github 和 gitee 上,可以使用如下命令行拉取代碼。我整個(gè)代碼倉(cāng)庫(kù)比較龐大,使用以下命令行可以進(jìn)行部分拉取,拉取速度比較快
先創(chuàng)建一個(gè)空文件夾,接著使用命令行 cd 命令進(jìn)入此空文件夾,在命令行里面輸入以下代碼,即可獲取到本文的代碼
git init
git remote add origin https://gitee.com/lindexi/lindexi_gd.git
git pull origin 75409caab083c6ccd3337de4e8159205314e6974
以上使用的是國(guó)內(nèi)的 gitee 的源,如果 gitee 不能訪(fǎng)問(wèn),請(qǐng)?zhí)鎿Q為 github 的源。請(qǐng)?jiān)诿钚欣^續(xù)輸入以下代碼,將 gitee 源換成 github 源進(jìn)行拉取代碼。如果依然拉取不到代碼,可以發(fā)郵件向我要代碼
git remote remove origin
git remote add origin https://github.com/lindexi/lindexi_gd.git
git pull origin 75409caab083c6ccd3337de4e8159205314e6974
獲取代碼之后,進(jìn)入 WPFDemo/NaihunojojeaKeheakabearweabe 文件夾,即可獲取到源代碼
更多技術(shù)博客,請(qǐng)參閱 博客導(dǎo)航
博客園博客只做備份,博客發(fā)布就不再更新,如果想看最新博客,請(qǐng)?jiān)L問(wèn) https://blog.lindexi.com/
如圖片看不見(jiàn),請(qǐng)?jiān)跒g覽器開(kāi)啟不安全http內(nèi)容兼容

本作品采用知識(shí)共享署名-非商業(yè)性使用-相同方式共享 4.0 國(guó)際許可協(xié)議進(jìn)行許可。歡迎轉(zhuǎn)載、使用、重新發(fā)布,但務(wù)必保留文章署名[林德熙](http://www.rzrgm.cn/lindexi)(包含鏈接:http://www.rzrgm.cn/lindexi ),不得用于商業(yè)目的,基于本文修改后的作品務(wù)必以相同的許可發(fā)布。如有任何疑問(wèn),請(qǐng)與我[聯(lián)系](mailto:lindexi_gd@163.com)。

浙公網(wǎng)安備 33010602011771號(hào)