P/Invoke WlanHostedNetworkQueryStatus from wlanapi.dll

P/Invoke WlanHostedNetworkQueryStatus from wlanapi.dll

本文关键字:wlanapi dll from WlanHostedNetworkQueryStatus Invoke      更新时间:2023-10-16

我已经映射了C++函数(来自WLanapi.dll):

DWORD WINAPI WlanHostedNetworkQueryStatus(
_In_        HANDLE hClientHandle,
_Out_       PWLAN_HOSTED_NETWORK_STATUS *ppWlanHostedNetworkStatus,
_Reserved_  PVOID pvReserved
);

至以下C#代码:

[DllImport("Wlanapi.dll", SetLastError = true)]
static extern UInt32 WlanHostedNetworkQueryStatus(
[In] IntPtr hClientHandle,
[Out] out _WLAN_HOSTED_NETWORK_STATUS ppWlanHostedNetworkStatus,
[In, Out] IntPtr pvReserved
);

我还映射了所需的所有结构和枚举以及其他内容(例如,获取clientHandle指针和启动托管网络)
_WLAN_HOSTED_NETWORK_STATUS的映射方式如下:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct _WLAN_HOSTED_NETWORK_STATUS
{
public _WLAN_HOSTED_NETWORK_STATE HostedNetworkState;
public Guid IPDeviceID;
public _DOT11_MAC_ADDRESS wlanHostedNetworkBSSID;
public _DOT11_PHY_TYPE dot11PhyType;
public UInt32 ulChannelFrequency;
public UInt32 dwNumberOfPeers;
public _WLAN_HOSTED_NETWORK_PEER_STATE[] PeerList;
}

现在,当执行该函数时,我不知道如何正确使用ppWlanHostedNetworkStatus等。该函数返回ERROR_SUCCESS(0),这意味着我已经调用了它并正确地传递了参数:

_WLAN_HOSTED_NETWORK_STATUS netStatus = new _WLAN_HOSTED_NETWORK_STATUS();
WlanHostedNetworkQueryStatus(clientHandle, out netStatus, IntPtr.Zero);

但是,在查询ppWlanHostedNetworkStatus的值(如网络状态或连接的对等体数量)时,我得到的只是一些奇怪的长整数(我会说内存地址,但我不确定),例如调用:

netStatus.HostedNetworkState.ToString();

返回

11465720

HostedNetworkState是一个枚举,定义如下:

public enum _WLAN_HOSTED_NETWORK_STATE
{
wlan_hosted_network_unavailable,
wlan_hosted_network_idle,
wlan_hosted_network_active
}

所以.toString()应该从枚举中返回其中一个字符串,对吧
我很确定这与指针等有关,因为在_WLAN_HOSTED_NETWORK_STATUS(MS文档)的文档中,它说在调用该函数之前,ppWlanHostedNetworkStatus应该是NULL,并且它本身就是指向结构的指针。。。

如何调试它?我正在C#中编码,VS 2012…

谢谢你的帮助。

-----EDIT-----
我进一步尝试用IntPtr作为参数映射函数,传递IntPtr.Zero和Marshal.PtrToStruct,但在尝试这样做时,我得到了AccessViolationException。。。

[DllImport("Wlanapi.dll", SetLastError = true)]
static extern UInt32 WlanHostedNetworkQueryStatus(
[In] IntPtr hClientHandle,
[Out] out IntPtr ppWlanHostedNetworkStatus,
[In, Out] IntPtr pvReserved
);

然后:

IntPtr ppStatus = IntPtr.Zero;
WlanHostedNetworkQueryStatus(clientHandle, out ppStatus, IntPtr.Zero);
_WLAN_HOSTED_NETWORK_STATUS netStatus = (_WLAN_HOSTED_NETWORK_STATUS)Marshal.PtrToStructure(ppStatus, typeof(_WLAN_HOSTED_NETWORK_STATUS));

------编辑2---

根据Fermat2357的建议,我取消了要映射的结构的注释,并将以下内容更改为指针到指针的计数:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct _WLAN_HOSTED_NETWORK_STATUS
{
public _WLAN_HOSTED_NETWORK_STATE HostedNetworkState;
public Guid IPDeviceID;
public _DOT11_MAC_ADDRESS wlanHostedNetworkBSSID;
public _DOT11_PHY_TYPE dot11PhyType;
public UInt32 ulChannelFrequency;
public UInt32 dwNumberOfPeers;
//public _WLAN_HOSTED_NETWORK_PEER_STATE[] PeerList;
}

我这样称呼它:

IntPtr ppStatus = IntPtr.Zero;
WlanHostedNetworkQueryStatus(clientHandle, out ppStatus, IntPtr.Zero);
IntPtr ppStatus2 = new IntPtr(ppStatus.ToInt32());
_WLAN_HOSTED_NETWORK_STATUS stat = (_WLAN_HOSTED_NETWORK_STATUS)Marshal.PtrToStructure(ppStatus2, typeof(_WLAN_HOSTED_NETWORK_STATUS));
netStatus = stat.HostedNetworkState.ToString();

这最终给了我正确的网络状态(启动后处于活动状态)。。。现在我必须找到一种方法来整理这个动态数组
感谢迄今为止Fermat2357 的帮助

您的映射不正确。查看API函数WlanHostedNetworkQueryStatus的定义。

DWORD WINAPI WlanHostedNetworkQueryStatus(
_In_        HANDLE hClientHandle,
_Out_       PWLAN_HOSTED_NETWORK_STATUS *ppWlanHostedNetworkStatus,
_Reserved_  PVOID pvReserved
);

请注意,参数ppWlanHostedNetworkStatus是指向WLAN_HOSTED_NETWORK_STATUS结构的指针的指针。深入查看功能文档,您会发现

ppWlanHostedNetworkStatus[out]

输入时,此参数必须为NULL。

在输出时,如果对WlanHostedNetworkQueryStatus函数的调用成功,则此参数将接收一个指向无线托管网络当前状态的指针。当前状态以WLAN_HOSTED_NETWORK_status结构返回。

如果您提供NULL指针(如文档中所述),底层API将为您分配一个缓冲区,用于保存结构并初始化指向该缓冲区的指针。稍后别忘了打电话给WlanFreeMemory来释放它。否则,您将在此处发生资源泄漏。

然而,该功能的文档似乎并非100%完整。在我的测试(Win7 32Bit)中,如果您将指针初始化到足够大的内存缓冲区,API将不会为您分配内存。在这种情况下,似乎没有必要稍后调用WlanFreeMemory。但在这种情况下,很难猜测以下WLAN_HOSTED_NETWORK_PEER_STATE结构需要多少内存。出于这个原因,这似乎无论如何都不可用

这是我用来测试的C代码

#include <Wlanapi.h>
int _tmain(int argc, _TCHAR* argv[])
{
DWORD dwRes;
HANDLE hHandle;
DWORD negotiatedVersion;
dwRes = WlanOpenHandle(1, NULL, &negotiatedVersion, &hHandle);
if (ERROR_SUCCESS == dwRes)
{
PWLAN_HOSTED_NETWORK_STATUS pStatus = NULL;
dwRes = WlanHostedNetworkQueryStatus(hHandle, &pStatus, NULL);
if (ERROR_SUCCESS == dwRes)
{
if (wlan_hosted_network_unavailable != pStatus->HostedNetworkState)
{
// Do something with the result
}
WlanFreeMemory(pStatus);
}
else
{
// handle Error
}
WlanCloseHandle(hHandle, NULL);
}
else
{
// handle Error
}
return 0;
}

如果你想让你的样本工作,你需要修改封送结构的方式。

编辑

要正确封送,您可以尝试以下操作:

...
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct _WLAN_HOSTED_NETWORK_STATUS
{
public _WLAN_HOSTED_NETWORK_STATE HostedNetworkState;
public Guid IPDeviceID;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 6)]
public string wlanHostedNetworkBSSID;
public _DOT11_PHY_TYPE dot11PhyType;
public UInt32 ulChannelFrequency;
public UInt32 dwNumberOfPeers;
public _WLAN_HOSTED_NETWORK_PEER_STATE PeerList;
}
...
IntPtr ptr = new IntPtr();
uint hostedNetworkQueryStatusSuccess = WlanHostedNetworkQueryStatus(clientHandle, out ptr, IntPtr.Zero);
if (openHandleSuccess == 0)
{
var netStat = (_WLAN_HOSTED_NETWORK_STATUS)Marshal.PtrToStructure(ptr, typeof(_WLAN_HOSTED_NETWORK_STATUS));
Console.WriteLine(netStat.HostedNetworkState);
if (netStat.HostedNetworkState != _WLAN_HOSTED_NETWORK_STATE.wlan_hosted_network_unavailable)
{
IntPtr offset = Marshal.OffsetOf(typeof(_WLAN_HOSTED_NETWORK_STATUS), "PeerList");
for (int i = 0; i < netStat.dwNumberOfPeers; i++)
{
var peer = (_WLAN_HOSTED_NETWORK_PEER_STATE)Marshal.PtrToStructure(
new IntPtr(ptr.ToInt64() + offset.ToInt64()), 
typeof(_WLAN_HOSTED_NETWORK_PEER_STATE));
System.Console.WriteLine(peer.PeerMacAddress);
offset += Marshal.SizeOf(peer);
}
}
}

想法:我在这里使用了一个结构,我可以确保它一直都是正确的。后来,随着对dwNumberOfPeers成员的了解(如果它是有效的),我一步一步地得到了所有的内部结构。

EDIT:要尝试的一件事是我用来帮助调试的一个技巧-用字节数组替换你的结构,看看你能收回什么(好吧,在这种情况下是uint数组):

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct _WLAN_HOSTED_NETWORK_STATUS
{
[MarshalAs(UnmanagedType.ByValArray, ArraySubType=UnmanagedType.U4, SizeConst = 48)]
public uint[] scratch;
}

然而,当我在本地运行时,我得到了非常奇怪的值——第一个(10x4)=40字节被清零:

0 0 0 0 
0 0 0 0 
0 0 4D454D4C 28 
16DCD870 0 787F6447 80000020 
...omitted...

尝试这组p/Invoke声明:

(在LINQPad中完成,因此相应地替换"转储"方法)

void Main()
{
IntPtr clientHandle;
int negotiatedVersion;
if(WlanOpenHandle(2, IntPtr.Zero, out negotiatedVersion, out clientHandle) != 0)
{
throw new InvalidOperationException("Could not open handle");
}
Console.WriteLine("Negotiated version:{0}", negotiatedVersion);
IntPtr pNetStatus = IntPtr.Zero;
if(WlanHostedNetworkQueryStatus(clientHandle, out pNetStatus, IntPtr.Zero) != 0)
{
throw new InvalidOperationException("Could not query network status");
}
var netStatus = (WLAN_HOSTED_NETWORK_STATUS)Marshal.PtrToStructure(pNetStatus, typeof(WLAN_HOSTED_NETWORK_STATUS));
Console.WriteLine(netStatus.PeerList[0]);
WlanFreeMemory(pNetStatus);
WlanCloseHandle(clientHandle, IntPtr.Zero);
}

[DllImport("Wlanapi.dll", SetLastError = true)]
[return:MarshalAs(UnmanagedType.Bool)]
public static extern bool WlanOpenHandle(
[In] int dwClientVersion,
IntPtr pReserved,
[Out] out int pdwNegotiatedVersion,
[Out] out IntPtr phClientHandle
);
[DllImport("Wlanapi.dll", SetLastError = true)]
[return:MarshalAs(UnmanagedType.Bool)]
public static extern bool WlanCloseHandle(
[In] IntPtr hClientHandle,
IntPtr pReserved
);
[DllImport("Wlanapi.dll", SetLastError = true)]
static extern UInt32 WlanHostedNetworkQueryStatus(
[In] IntPtr hClientHandle,
[Out] out IntPtr ppWlanHostedNetworkStatus,
[In, Out] IntPtr pvReserved
);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct _WLAN_HOSTED_NETWORK_STATUS
{
public _WLAN_HOSTED_NETWORK_STATE HostedNetworkState;
public Guid IPDeviceID;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=6)]
public string wlanHostedNetworkBSSID;
public _DOT11_PHY_TYPE dot11PhyType;
public UInt32 ulChannelFrequency;
public UInt32 dwNumberOfPeers;
public IntPtr PeerList;
}
public enum _WLAN_HOSTED_NETWORK_STATE 
{ 
wlan_hosted_network_unavailable,
wlan_hosted_network_idle,
wlan_hosted_network_active
}
public enum _DOT11_PHY_TYPE : uint
{ 
dot11_phy_type_unknown     = 0,
dot11_phy_type_any         = 0,
dot11_phy_type_fhss        = 1,
dot11_phy_type_dsss        = 2,
dot11_phy_type_irbaseband  = 3,
dot11_phy_type_ofdm        = 4,
dot11_phy_type_hrdsss      = 5,
dot11_phy_type_erp         = 6,
dot11_phy_type_ht          = 7,
dot11_phy_type_IHV_start   = 0x80000000,
dot11_phy_type_IHV_end     = 0xffffffff
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct _WLAN_HOSTED_NETWORK_PEER_STATE 
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=6)]
public string PeerMacAddress;
_WLAN_HOSTED_NETWORK_PEER_AUTH_STATE PeerAuthState;
}
public enum _WLAN_HOSTED_NETWORK_PEER_AUTH_STATE 
{ 
wlan_hosted_network_peer_state_invalid,
wlan_hosted_network_peer_state_authenticated
}