3

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() は、列挙からこれらの文字列の 1 つを返す必要がありましたよね?
_WLAN_HOSTED_NETWORK_STATUS ( MS documentation ) のドキュメントでは、その関数を呼び出す前に、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

4

2 に答える 2

2

マッピングが正しくありません。API 関数WlanHostedNetworkQueryStatusの定義を見てください。

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

注意してください、パラメーターは構造体ppWlanHostedNetworkStatusへのポインターへのポインターです。WLAN_HOSTED_NETWORK_STATUS見つけた関数のドキュメントを詳しく見てください

ppWlanHostedNetworkStatus [アウト]

入力では、このパラメーターは 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 メンバーの知識 (有効な場合) を使用して、すべての内部構造を段階的に取得します。

于 2012-12-10T16:51:52.033 に答える
0

編集:試してみることの1つは、デバッグを支援するために使用するトリックです-構造体をバイト配列に置き換え、何を引き戻すかを確認します(この場合は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 で行われるため、それに応じて "Dump" メソッドを置き換えます)

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
}
于 2012-12-10T17:06:02.983 に答える