C# 调用LoadLibrary然后调用FreeLibrary会中断网络

C# 调用LoadLibrary然后调用FreeLibrary会中断网络,c#,winapi,C#,Winapi,今天偶然发现了一些非常奇怪的行为,并将其缩小为复制代码: TcpListener Listener = new TcpListener(System.Net.IPAddress.Any, 8888); Listener.Start(); TcpClient Client = new TcpClient("localhost", 8888); IntPtr ModuleHandle = WinApi.LoadLibraryW(@"C:\Windows\system32

今天偶然发现了一些非常奇怪的行为,并将其缩小为复制代码:

TcpListener Listener = new TcpListener(System.Net.IPAddress.Any, 8888);
Listener.Start();
TcpClient Client = new TcpClient("localhost", 8888);
IntPtr ModuleHandle = WinApi.LoadLibraryW(@"C:\Windows\system32\ipnathlp.dll"); // <-- Any other DLL here and everything is fine
WinApi.FreeLibrary(ModuleHandle); // <-- Remove this line and everything is fine
byte[] Bytes = new byte[2];
Client.GetStream.Write(Bytes, 0, 2); // <-- Exception thrown here if FreeLibrary is called above:
                                     // "Unable to write data to the transport connection: Either the application
                                     // has not called WSAStartup, or WSAStartup failed."
从注释中可以看到,使用此特定DLL(
C:\Windows\system32\ipnathlp.DLL
)调用
LoadLibrary
),然后使用
freebrary
将其释放,这使得我无法在网络流中发送数据,而不会得到有关WSASTARTP的奇怪异常

此DLL与windows防火墙和网络相关(其描述为“Microsoft NAT Helper Components”),但不管怎样,
LoadLibrary
不应该只是将引用计数增加1,然后
FreeLibrary
将其减少1吗(因此,如果我只加载一次,然后卸载一次,它应该不会对程序的其余部分产生任何影响)

执行以下任何操作都可以阻止此问题的发生,并使一切正常工作:

  • 将目标CPU更改为x86而不是x64
  • LoadLibrary
    Dll导入语句中指定
    CharSet=Ansi
    (虽然我调用的是unicode版本的LoadLibraryW,.NET都是unicode,但我觉得我不应该这样做,而且我以前从来没有在.NET中调用过任何其他Win32 API)
  • 删除对
    FreeLibrary的调用

这是在Windows 7 64位计算机上。还没有机会在任何其他计算机上进行测试。

为什么需要
LoadLibraryW
然后
freebrary
?看起来像
DllMain()
中的
ipnathlp.dll
dll\u分离过程中调用
WSACleanup()
,但不调用
WSAStartup()
DLL\u进程\u ATTACH期间
。它不应该调用其中任何一个,但调用其中一个而不是另一个都会被破坏;您需要通过调用
WSAStartup()来解决它
自己加载或避免加载
ipnathlp.dll
。ipnathlp.dll不是公共Windows API表面的一部分。它是Windows的内部实现细节,您的应用程序不需要加载该模块。@Luke感谢您的完美解释。如果您将其作为答案发布,我将接受它。如果您调用
LoadLibrary
,您加载它的目的是从中运行代码。如果您只需要访问它的资源,请改用。但这并不会改变这种情况:此模块是一个实现细节,您的代码不需要使用它,即使只是从它的资源中读取。有一个完整的专用(部分)解释这样的违规行为是如何出错的。为什么需要
LoadLibraryW
然后
freebrary
?看起来像
ipnathlp.dll中的
DllMain()
dll\u分离过程中调用
WSACleanup()
,但不调用
WSAStartup()
DLL\u进程\u ATTACH期间
。它不应该调用其中任何一个,但调用其中一个而不是另一个都会被破坏;您需要通过调用
WSAStartup()来解决它
自己加载或避免加载
ipnathlp.dll
。ipnathlp.dll不是公共Windows API表面的一部分。它是Windows的内部实现细节,您的应用程序不需要加载该模块。@Luke感谢您的完美解释。如果您将其作为答案发布,我将接受它。如果您调用
LoadLibrary
,您加载它的目的是从中运行代码。如果您只需要访问它的资源,请改用。但这并不会改变这种情况:此模块是一个实现细节,您的代码不需要使用它,即使只是从它的资源中读取。有一个完整的专用(部分)来解释这样的违规行为是如何变成错误的。
[DllImport("kernel32.dll", EntryPoint = "FreeLibrary", SetLastError = true)]
public static extern bool FreeLibrary([In] IntPtr hLibModule);

[DllImport("kernel32.dll", EntryPoint = "LoadLibraryW", SetLastError = true)]
public static extern IntPtr LoadLibraryW([In][MarshalAs(UnmanagedType.LPWStr)] string lpLibFileName);