Solved

dllimport help from c, c++ unmanaged dll to managed c# wrapper

Posted on 2007-11-25
51
1,278 Views
Last Modified: 2013-11-26
Bear in mind I am a vb.net guru and I know very little about c or c++k or c#.  I have successfully wrapped a couple functions from an unmanaged dll but  this one is tougher.  I need some help with the interface wrapper.  

OH and in the snippit is contained  big stinkin C header file (another thing I know little about!

This is the actual API from the source code of the DLL



struct _AirpcapHandle
{
      HANDLE OsHandle;                  
      HANDLE ReadEvent;
      UINT Flags;      // Currently unused
      AIRPCAP_ADAPTER_TYPE AdapterType;
      HKEY hKey;
      AirpcapChannelInfo *pChannels;
      ULONG NumChannels;

      CHAR Ebuf[AIRPCAP_ERRBUF_SIZE];
};


PAirpcapHandle AirpcapOpen(PCHAR DeviceName, PCHAR Ebuf)
{
      int retcode = 0;
      DWORD BytesReturned;
      PAirpcapHandle AdapterHandle;
      HANDLE hEvent;
      CHAR CompleteName[256];
      UINT DeviceNumber;
      AirpcapLinkType AdLinkType;
      ULONG      IoctlCode;
      AirpcapDecryptionState GlobalDecryptionState;
      AirpcapKeysCollection FakeCollection;
      PAirpcapKeysCollection pKeysCollection;
      UINT collectionSize;

#ifdef HAVE_AR5416_SUPPORT
      AIRPCAP_ADAPTER_TYPE AdapterType = ADAPTER_TYPE_AIRPCAP_DRIVER;

#endif//HAVE_AR5416_SUPPORT

#ifdef HAVE_AR5416_SUPPORT

      if (strcmp(DeviceName, ATHEROS_ADAPTER_NAME_0_A) == 0)
      {
            AdapterType = ADAPTER_TYPE_AR5416_DRIVER;
            _snprintf(
                  CompleteName,
                  sizeof(CompleteName) - 1,
                  "%s",
                  DEVICE_GLOBAL_NAME_0_A);
            CompleteName[sizeof(CompleteName) -1] = '\0';
      }
      else
      if (strcmp(DeviceName, ATHEROS_ADAPTER_NAME_1_A) == 0)
      {
            AdapterType = ADAPTER_TYPE_AR5416_DRIVER;
            _snprintf(
                  CompleteName,
                  sizeof(CompleteName) - 1,
                  "%s",
                  DEVICE_GLOBAL_NAME_1_A);
            CompleteName[sizeof(CompleteName) -1] = '\0';
      }
      else
      {
#endif//HAVE_AR5416_SUPPORT
            //
            // Add the global prefix to make it possible to open the device from terminal services
            //
            if(sscanf(DeviceName, AIRPCAP_DEVICE_NUMBER_EXTRACT_STRING, &DeviceNumber) != 1)
            {
                  if(strcmp(DeviceName, DEVICESTRING_ANY_NO_PREFIX) == 0)
                  {
                        // This is the any device
                        _snprintf(CompleteName, sizeof(CompleteName), DEVICESTRING_ANY);
                        goto SuccesfulMatch;
                  }
                  else
                  {
                        // This is not airpcap
                        _snprintf(Ebuf, AIRPCAP_ERRBUF_SIZE, "Unable to open device - wrong device name\n");
                        return NULL;
                  }
            }
            else
            {
                  // This is a regular device
                  _snprintf(CompleteName, sizeof(CompleteName), DEVICESTRING, DeviceNumber);
            }
#ifdef HAVE_AR5416_SUPPORT
      }
#endif //HAVE_AR5416_SUPPORT

SuccesfulMatch:

      //
      // Allocate the handlde
      //
      AdapterHandle = (PAirpcapHandle)malloc(sizeof(AirpcapHandle));
      if(!AdapterHandle)
      {
            _snprintf(Ebuf, AIRPCAP_ERRBUF_SIZE, "Memory allocation failure\n");
            return NULL;
      }
      
      AdapterHandle->hKey = INVALID_HANDLE_VALUE;

      //
      // Open the device
      //
      AdapterHandle->OsHandle = CreateFile(CompleteName, MAXIMUM_ALLOWED, 0, NULL, OPEN_EXISTING,  FILE_ATTRIBUTE_NORMAL, NULL);
      if(AdapterHandle->OsHandle == INVALID_HANDLE_VALUE)
      {
            _snprintf(Ebuf, AIRPCAP_ERRBUF_SIZE, "Unable to open device - error %d\n", GetLastError());
            free(AdapterHandle);
            return NULL;
      }

#ifdef HAVE_AR5416_SUPPORT
      if (AdapterType == ADAPTER_TYPE_AR5416_DRIVER)
      {
            if (DeviceIoControl(AdapterHandle->OsHandle, ATH_CAP_IOCTL_BINDTOADAPTER, NULL, 0, NULL, 0, &BytesReturned, NULL) == FALSE)
            {
                  _snprintf(Ebuf, AIRPCAP_ERRBUF_SIZE, "Unable to bind to device - error %u\n", GetLastError());
                  CloseHandle(AdapterHandle->OsHandle);
                  free(AdapterHandle);
                  return FALSE;
            }
      }
#endif
      
      //
      // Open the event for this device
      //
      hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

      if(hEvent == NULL)
      {
            _snprintf(Ebuf, AIRPCAP_ERRBUF_SIZE, "Unable to set the read event: %d\n", GetLastError());
            CloseHandle(AdapterHandle->OsHandle);
            free(AdapterHandle);
            return FALSE;
      }

#ifdef HAVE_AR5416_SUPPORT
      if (AdapterType == ADAPTER_TYPE_AR5416_DRIVER)
      {
            //
            // AIRPCAP DRIVER
            //
            IoctlCode = ATH_CAP_IOCTL_SETREADEVENT;
      }
      else
#endif //HAVE_AR5416_SUPPORT
      {
            //
            // AIRPCAP DRIVER
            //
            IoctlCode = IOCTL_SETSHAREDEVENT;
      }

      if(DeviceIoControl(AdapterHandle->OsHandle,
                  IoctlCode,
                  &hEvent,
                  sizeof(hEvent),
                  NULL,
                  0,
                  &BytesReturned,
                  NULL)==FALSE)
      {
            _snprintf(Ebuf, AIRPCAP_ERRBUF_SIZE, "Unable to set the read event: %d\n", GetLastError());
            CloseHandle(hEvent);
            CloseHandle(AdapterHandle->OsHandle);
            free(AdapterHandle);
            return FALSE;
      }

      AdapterHandle->ReadEvent = hEvent;
      AdapterHandle->AdapterType = AdapterType;

#ifdef HAVE_AR5416_SUPPORT
      if (AdapterType == ADAPTER_TYPE_AR5416_DRIVER)
      {
            if (BindToAr5416ConfigurationRegistry(AdapterHandle) != TRUE)
            {
                  _snprintf(Ebuf, AIRPCAP_ERRBUF_SIZE, "Cannot access the default device configuration from the registry\n");
                  CloseHandle(hEvent);
                  CloseHandle(AdapterHandle->OsHandle);
                  free(AdapterHandle);
                  return FALSE;
            }
      }
#endif //HAVE_AR5416_SUPPORT

      //
      // Detect if this is this instance has a radio header. We need this information to properly
      // decode packets that will be transmitted.
      //
      if(!AirpcapGetLinkType(AdapterHandle, &AdLinkType))
      {
            _snprintf(Ebuf, AIRPCAP_ERRBUF_SIZE, "Unable to get the adapter linktype: %s\n", AdapterHandle->Ebuf);
            CloseHandle(hEvent);
            CloseHandle(AdapterHandle->OsHandle);
            if (AdapterHandle->hKey != INVALID_HANDLE_VALUE) RegCloseKey(AdapterHandle->hKey);
            free(AdapterHandle);
            return FALSE;
      }

      switch(AdLinkType)
      {
      case AIRPCAP_LT_802_11_PLUS_RADIO:
                  AdapterHandle->Flags = AdapterHandle->Flags | AIRPCAP_FLAGS_IS_RADIOTAP;
            break;
      case AIRPCAP_LT_802_11_PLUS_PPI:
                  AdapterHandle->Flags = AdapterHandle->Flags | AIRPCAP_FLAGS_IS_PPI;
            break;
      default:
            AdapterHandle->Flags = AdapterHandle->Flags & ~AIRPCAP_FLAGS_IS_RADIOTAP;
            AdapterHandle->Flags = AdapterHandle->Flags & ~AIRPCAP_FLAGS_IS_PPI;
      }

      //
      // Get the list of channels from the driver. The code is the same, but the IOCTL number is different for the
      // airpcap and atheros driver.
      //
#ifdef HAVE_AR5416_SUPPORT
      if(AdapterType == ADAPTER_TYPE_AR5416_DRIVER)
      {
            IoctlCode = ATH_CAP_IOCTL_GETSUPPORTEDCHANNELINFO;
      }
      else
#endif //HAVE_AR5416_SUPPORT
      {
            IoctlCode = IOCTL_GETSUPPORTEDCHANNELINFO;
      }

      if(DeviceIoControl(AdapterHandle->OsHandle, IoctlCode, NULL, 0, NULL, 0, &BytesReturned, NULL) == TRUE)
      {
            AdapterHandle->pChannels = NULL;
            AdapterHandle->NumChannels = 0;
      }
      else
      {
            if(GetLastError() != ERROR_MORE_DATA)
            {
                  AdapterHandle->pChannels = NULL;
                  AdapterHandle->NumChannels = 0;
            }
            else
            {
                  AdapterHandle->pChannels = (AirpcapChannelInfo*)malloc(BytesReturned);

                  //
                  // The AirPcapN driver doesn't set the flags, so we clear the memory to be sure we don't get garbage values.
                  //
                  memset(AdapterHandle->pChannels, 0, BytesReturned);
      
                  if(AdapterHandle->pChannels == NULL)
                  {
                        _snprintf(Ebuf, AIRPCAP_ERRBUF_SIZE, "Memory allocation failure\n");
                        CloseHandle(hEvent);
                        CloseHandle(AdapterHandle->OsHandle);
                        if (AdapterHandle->hKey != INVALID_HANDLE_VALUE) RegCloseKey(AdapterHandle->hKey);
                        free(AdapterHandle);
                        AdapterHandle = NULL;
                        goto OpenDone;
                  }

                  if(DeviceIoControl(AdapterHandle->OsHandle, IoctlCode, NULL, 0, AdapterHandle->pChannels, BytesReturned, &BytesReturned, NULL) == TRUE)
                  {
                        AdapterHandle->NumChannels = BytesReturned / sizeof(AirpcapChannelInfo);
                  }
                  else
                  {
                        _snprintf(Ebuf, AIRPCAP_ERRBUF_SIZE, "Unable to retrieve the supported channels: %d\n", GetLastError());
                        CloseHandle(hEvent);
                        CloseHandle(AdapterHandle->OsHandle);
                        if (AdapterHandle->hKey != INVALID_HANDLE_VALUE) RegCloseKey(AdapterHandle->hKey);
                        free(AdapterHandle->pChannels);
                        free(AdapterHandle);
                        AdapterHandle = NULL;
                        goto OpenDone;
                  }
            }
      }

      //
      // obtain the decryption state from the airpcap key store and inject it to the driver
      // NOTE: for the airpcap driver, this setting is saved in the airpcap driver reg hives
      //       but we ignore it. This is because this is a global airpcap.dll setting, while
      //       the airpcap driver registry hive can be accessed by the airpcap driver only
      //
      if (ReadDecryptionStateFromAirpcapGlobalKeyStore(&GlobalDecryptionState, Ebuf) == FALSE)
      {
            CloseHandle(hEvent);
            CloseHandle(AdapterHandle->OsHandle);
            if (AdapterHandle->hKey != INVALID_HANDLE_VALUE) RegCloseKey(AdapterHandle->hKey);
            free(AdapterHandle->pChannels);
            free(AdapterHandle);
            AdapterHandle = NULL;
            goto OpenDone;
      }

      if (AirpcapSetDecryptionState(AdapterHandle, GlobalDecryptionState) == FALSE)
      {
            _snprintf(Ebuf, AIRPCAP_ERRBUF_SIZE, "%s", AdapterHandle->Ebuf);
            CloseHandle(hEvent);
            CloseHandle(AdapterHandle->OsHandle);
            if (AdapterHandle->hKey != INVALID_HANDLE_VALUE) RegCloseKey(AdapterHandle->hKey);
            free(AdapterHandle->pChannels);
            free(AdapterHandle);
            AdapterHandle = NULL;
            goto OpenDone;
      }

      //
      // Now obtain the global decryption keys from the key store and inject them in driver
      // instance controlling the adapter we are opening. We know that this introduces a bit of
      // overhead (we are setting a per-driver parameter at every adapter open, but this is the
      // only way we can guarantee that the driver keys are set in the airpcapn driver, which doesnt
      // have any way to persist such keys on a per driver basis in a common place (common to the
      // vanilla airpcap driver)
      //

      //
      // First we use a fake empty collection to know the number of keys in the global key store
      //
      collectionSize = sizeof(FakeCollection);

      if (ReadKeysFromAirpcapGlobalKeyStore(&FakeCollection, &collectionSize, Ebuf) == FALSE)
      {
            //
            // check if the buffer is just too small or what
            //
            if (collectionSize == 0)
            {
                  //
                  // severe error occurred, bail out
                  //
                  CloseHandle(hEvent);
                  CloseHandle(AdapterHandle->OsHandle);
                  if (AdapterHandle->hKey != INVALID_HANDLE_VALUE) RegCloseKey(AdapterHandle->hKey);
                  free(AdapterHandle->pChannels);
                  free(AdapterHandle);
                  AdapterHandle = NULL;
                  goto OpenDone;
            }

            //
            // ok, we just need to allocate a real collection
            //
            pKeysCollection = (PAirpcapKeysCollection)malloc(collectionSize);

            if (pKeysCollection == NULL)
            {
                  _snprintf(Ebuf, AIRPCAP_ERRBUF_SIZE, "Memory allocation failure\n");
                  CloseHandle(hEvent);
                  CloseHandle(AdapterHandle->OsHandle);
                  if (AdapterHandle->hKey != INVALID_HANDLE_VALUE) RegCloseKey(AdapterHandle->hKey);
                  free(AdapterHandle->pChannels);
                  free(AdapterHandle);
                  AdapterHandle = NULL;
                  goto OpenDone;
            }
            
            if (ReadKeysFromAirpcapGlobalKeyStore(pKeysCollection, &collectionSize, Ebuf) == FALSE)
            {
                  //
                  // something really bad happened, the buffer we allocated is not big enough
                  // or similar. Just fail the open request
                  //
                  free(pKeysCollection);
                  CloseHandle(hEvent);
                  CloseHandle(AdapterHandle->OsHandle);
                  if (AdapterHandle->hKey != INVALID_HANDLE_VALUE) RegCloseKey(AdapterHandle->hKey);
                  free(AdapterHandle->pChannels);
                  free(AdapterHandle);
                  AdapterHandle = NULL;
                  goto OpenDone;
            }

            //
            // now set the keys
            //
            if (SetDriverKeysInternal(
                  AdapterHandle,
                  pKeysCollection,
                  FALSE,            // do not store the keys in the global key store. We just retrieved them from there
                  FALSE            // do not store the keys in all the drivers, just the one responsible for the AdapterHandle
                        ) == FALSE)
            {
                  _snprintf(Ebuf, AIRPCAP_ERRBUF_SIZE, "%s", AdapterHandle->Ebuf);
                  CloseHandle(hEvent);
                  CloseHandle(AdapterHandle->OsHandle);
                  if (AdapterHandle->hKey != INVALID_HANDLE_VALUE) RegCloseKey(AdapterHandle->hKey);
                  free(AdapterHandle->pChannels);
                  free(AdapterHandle);
                  AdapterHandle = NULL;
                  free(pKeysCollection);
                  goto OpenDone;
            }

            free(pKeysCollection);
      }
      else
      {
            //
            // if we are here it means that we succeded but no keys were available in the key store.
            // Dont even try to set the keys in the driver, by default the driver starts without keys
            //
      }

OpenDone:

      return AdapterHandle;
}

///////////////////////////////////////////////////////////////////

//airpcap.h
 

/*

 * Copyright (c) 2006-2007 CACE Technologies, Davis (California)

 * All rights reserved.

 *

 * Redistribution and use in source and binary forms, with or without

 * modification, are permitted.

 *

 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

 *

 */
 

#if !defined(AIRPCAP_H__EAE405F5_0171_9592_B3C2_C19EC426AD34__INCLUDED_)

#define AIRPCAP_H__EAE405F5_0171_9592_B3C2_C19EC426AD34__INCLUDED_
 

#ifdef _MSC_VER

// This disables a VS warning for zero-sized arrays.

#pragma warning( disable : 4200)

// This stops VS2005 ranting against stdio.

#pragma warning( disable : 4996)

#endif 
 

#ifdef __cplusplus

extern "C" {

#endif
 

/*!

	\mainpage AirPcap interface documentation

	

	\section Introduction
 

	This document describes the data structures and the functions exported by the CACE Technologies AirPcap library.

	The AirPcap library provides low-level access to the AirPcap devices including advanced capabilities such as channel setting,

	link type control and WEP configuration.<br>

	This manual includes the following sections:
 

	- \ref airpcapfuncs

	- \ref airpcapdefs

	- \ref radiotap
 

	\note Throughout this documentation, \e device refers to a physical AirPcap device, while \e adapter is an open API

	instance. Most of the AirPcap API operations are adapter-specific but some of them, like setting the channel, are

	per-device and will be reflected on all the open adapters. These functions will have "Device" in their name, e.g.

	AirpcapSetDeviceChannel().
 

*/
 

/** @defgroup airpcapdefs AirPcap definitions and data structures

 *  @{

 */
 

/*!

  \brief This string is the fixed prefix in the airpcap adapter name. 

  It can be used to parse the name field in an AirpcapDeviceDescription structure.

*/

#define AIRPCAP_DEVICE_NAME_PREFIX		"\\\\.\\airpcap"
 

/*!

  \brief This string is the scanf modifier to extract the adapter number from an adapter name. 

  It can be used to parse the name field in an AirpcapDeviceDescription structure with scanf.

*/

#define AIRPCAP_DEVICE_NUMBER_EXTRACT_STRING		 "\\\\.\\airpcap%u"
 

/*!

  \brief Entry in the list returned by \ref AirpcapGetDeviceList().

*/

typedef struct _AirpcapDeviceDescription

{

	struct	_AirpcapDeviceDescription *next;			///< Next element in the list

	PCHAR	Name;										///< Device name

	PCHAR	Description;								///< Device description

} AirpcapDeviceDescription, *PAirpcapDeviceDescription;
 

#define MAX_ENCRYPTION_KEYS 64
 

#define WEP_KEY_MAX_SIZE 32		///< Maximum size of a WEP key, in bytes. This is the size of an entry in the 

								///< AirpcapWepKeysCollection structure
 

#ifndef __MINGW32__

#pragma pack(push)

#pragma pack(1)

#endif // __MINGW32__
 
 

#define AIRPCAP_KEYTYPE_WEP		0	///< Key type: WEP. The key can have an arbitrary length smaller than 32 bytes.

#define AIRPCAP_KEYTYPE_TKIP	1	///< Key type: TKIP (WPA). NOT SUPPORTED YET.

#define AIRPCAP_KEYTYPE_CCMP	2	///< Key type: CCMP (WPA2). NOT SUPPORTED YET.
 

/*!

  \brief WEP key container

*/

typedef struct _AirpcapKey

{

	UINT KeyType;						///< Type of key, can be on of: \ref AIRPCAP_KEYTYPE_WEP, \ref AIRPCAP_KEYTYPE_TKIP, \ref AIRPCAP_KEYTYPE_CCMP. Only AIRPCAP_KEYTYPE_WEP is supported by the driver at the moment.

	UINT KeyLen;						///< Length of the key, in bytes

	BYTE KeyData[WEP_KEY_MAX_SIZE];		///< Key Data

}

#ifdef __MINGW32__

__attribute__((__packed__))

#endif // __MINGW32__

AirpcapKey, *PAirpcapKey;
 

/*!

  \brief frequency Band.

   802.11 adapters can support different frequency bands, the most important of which are: 2.4GHz (802.11b/g/n) 

   and 5GHz (802.11a/n).

*/

typedef enum _AirpcapChannelBand

{

    AIRPCAP_CB_AUTO = 1,				///< Automatically pick the best frequency band

    AIRPCAP_CB_2_4_GHZ = 2,				///< 2.4 GHz frequency band

    AIRPCAP_CB_4_GHZ = 4,				///< 4 GHz frequency band

    AIRPCAP_CB_5_GHZ = 5				///< 5 GHz frequency band

}AirpcapChannelBand, *PAirpcapChannelBand;
 

/*!

  \brief Type of frame validation the adapter performs.

   An adapter can be instructed to accept different kind of frames: correct frames only, frames with wrong Frame Check Sequence (FCS) only, all frames.

*/

typedef enum _AirpcapValidationType

{

    AIRPCAP_VT_ACCEPT_EVERYTHING = 1,		///< Accept all the frames the device captures

    AIRPCAP_VT_ACCEPT_CORRECT_FRAMES = 2,	///< Accept correct frames only, i.e. frames with correct Frame Check Sequence (FCS).

    AIRPCAP_VT_ACCEPT_CORRUPT_FRAMES = 3,	///< Accept corrupt frames only, i.e. frames with worng Frame Check Sequence (FCS).

	AIRPCAP_VT_UNKNOWN = 4					///< Unknown validation type. You should see it only in case of error.

}AirpcapValidationType, *PAirpcapValidationType;
 

/*!

  \brief Type of decryption the adapter performs.

   An adapter can be instructed to turn decryption (based on the device-configured keys configured 

   with \ref AirpcapSetDeviceKeys()) on or off.

*/

typedef enum _AirpcapDecryptionState

{

    AIRPCAP_DECRYPTION_ON = 1,				///< This adapter performs decryption

    AIRPCAP_DECRYPTION_OFF = 2				///< This adapter does not perform decryption

}AirpcapDecryptionState, *PAirpcapDecryptionState;
 
 

/*!

  \brief Storage for a MAC address

*/

typedef struct _AirpcapMacAddress

{

	BYTE Address[6];		///< MAC address bytes

}

#ifdef __MINGW32__

__attribute__((__packed__))

#endif // __MINGW32__

AirpcapMacAddress, *PAirpcapMacAddress;
 

/*!

  \brief This structure is used to store a collection of WEP keys. 

  Note that the definition of the structure doesn't contain any key, so be careful to allocate a buffer

  with the size of the key, like in the following example:
 

  \code

	PAirpcapKeysCollection KeysCollection;

	UINT KeysCollectionSize;

	

	KeysCollectionSize = sizeof(AirpcapKeysCollection) + NumKeys * sizeof(AirpcapKey);

	

	KeysCollection = (PAirpcapKeysCollection)malloc(KeysCollectionSize);

	if(!KeysCollection)

	{

		// Error

	}

  \endcode

*/

typedef struct _AirpcapKeysCollection

{

	UINT nKeys;												///< Number of keys in the collection

	AirpcapKey Keys[0];										///< Array of nKeys keys. 

} AirpcapKeysCollection, *PAirpcapKeysCollection;
 

/*!

  \brief Packet header.
 

  This structure defines the BPF that preceeds every packet delivered to the application.

*/

typedef struct _AirpcapBpfHeader 

{

	UINT TsSec;			///< Timestamp associated with the captured packet. SECONDS.

	UINT TsUsec;		///< Timestamp associated with the captured packet. MICROSECONDS.

	UINT Caplen;		///< Length of captured portion. The captured portion <b>can be different</b> from the original packet, because it is possible (with a proper filter) to instruct the driver to capture only a portion of the packets.

	UINT Originallen;	///< Original length of packet

	USHORT	Hdrlen;		///< Length of bpf header (this struct plus alignment padding). In some cases, a padding could be added between the end of this structure and the packet data for performance reasons. This field can be used to retrieve the actual data of the packet.

}

#ifdef __MINGW32__

__attribute__((__packed__))

#endif // __MINGW32__

AirpcapBpfHeader, *PAirpcapBpfHeader;
 

/// Helper macros to extract packets coming from the driver. Rounds up to the next even multiple of AIRPCAP_ALIGNMENT. 

#define AIRPCAP_ALIGNMENT sizeof(int)

#define AIRPCAP_WORDALIGN(x) (((x)+(AIRPCAP_ALIGNMENT-1))&~(AIRPCAP_ALIGNMENT-1))
 

#ifndef __MINGW32__

#pragma pack(pop)

#endif // __MINGW32__
 

#define AIRPCAP_ERRBUF_SIZE 512		///< Size of the error buffer, in bytes
 

/*!

  \brief Channel info flag: the channel is enabled for transmission, too.
 

  To comply with the electomagnetic emission regulations of the different countries, the AirPcap hardware can be programmed

  to block transmission on specific channels. This flag is set by AirpcapGetDeviceSupportedChannels() to indicate that a 

  channel in the list supports transmission.

*/

#define AIRPCAP_CIF_TX_ENABLED	0x1

	
 

/*!

  \brief Channel information.

  Used by \ref AirpcapSetDeviceChannelEx(), \ref AirpcapGetDeviceChannelEx(), \ref AirpcapGetDeviceSupportedChannels()

*/

typedef struct _AirpcapChannelInfo

{

	UINT Frequency;		///< Channel frequency, in MHz.

	/*! 

		\brief 802.11n specific. Offset of the extension channel in case of 40MHz channels. 

		

		Possible values are -1, 0 +1: 

		- -1 means that the extension channel should be below the control channel (e.g. Control = 5 and Extension = 1)

		- 0 means that no extension channel should be used (20MHz channels or legacy mode)

		- +1 means that the extension channel should be above the control channel (e.g. Control = 1 and Extension = 5)

		  

		In case of 802.11a/b/g channels (802.11n legacy mode), this field should be set to 0.

	*/

	CHAR ExtChannel;

	UCHAR Flags;		///< Channel Flags. The only flag supported at this time is \ref AIRPCAP_CIF_TX_ENABLED.

	UCHAR Reserved[2];	///< Reserved. It should be set to {0,0}.

}

AirpcapChannelInfo, *PAirpcapChannelInfo;
 

/*!

  \brief Link type. 

  

   AirPcap supports three 802.11 link types: 

   - plain 802.11 (\ref AIRPCAP_LT_802_11)

   - a radiotap header is prepended to each packet (\ref AIRPCAP_LT_802_11_PLUS_RADIO)

   - a PPI header is prepended to each packet (\ref AIRPCAP_LT_802_11_PLUS_PPI).

*/

typedef enum _AirpcapLinkType 

{

    AIRPCAP_LT_802_11 = 1,				///< plain 802.11 link type. Every packet in the buffer contains the raw 802.11 frame, including MAC FCS.

    AIRPCAP_LT_802_11_PLUS_RADIO = 2,	///< 802.11 plus radiotap link type. Every packet in the buffer contains a radiotap header followed by the 802.11 frame. MAC FCS is included.

	AIRPCAP_LT_UNKNOWN = 3,				///< Unknown link type. You should see it only in case of error.

	AIRPCAP_LT_802_11_PLUS_PPI = 4		///< 802.11 plus PPI header link type. Every packet in the buffer contains a PPI header followed by the 802.11 frame. MAC FCS is included.

}AirpcapLinkType, *PAirpcapLinkType;
 

#ifndef __AIRPCAP_DRIVER__
 

#if !defined(AIRPCAP_HANDLE__EAE405F5_0171_9592_B3C2_C19EC426AD34__DEFINED_)

#define AIRPCAP_HANDLE__EAE405F5_0171_9592_B3C2_C19EC426AD34__DEFINED_

/*!

  \brief Adapter handle.

*/

typedef struct _AirpcapHandle AirpcapHandle, *PAirpcapHandle;

#endif
 

/*!

  \brief Capture statistics.

   Returned by \ref AirpcapGetStats().

*/

typedef struct _AirpcapStats 

{

	UINT Recvs;			///< Number of packets that the driver received by the adapter 

						///< from the beginning of the current capture. This value includes the packets 

						///< dropped because of buffer full.

	UINT Drops;			///< number of packets that the driver dropped from the beginning of a capture. 

						///< A packet is lost when the the buffer of the driver is full. 

	UINT IfDrops;		///< Packets dropped by the card before going to the USB bus. 

						///< Not supported at the moment.

	UINT Capt;			///< number of packets that pass the BPF filter, find place in the kernel buffer and

						///< therefore reach the application.

}AirpcapStats, *PAirpcapStats;
 

// MAC flags

#define AIRPCAP_MF_MONITOR_MODE_ON		1	///< If set, the device is configured to work in monitor mode.

											///< When monitor mode is on, the device captures all the frames transmitted on the channel. This includes:

											///<    - unicast packets

											///<    - multicast packets

											///<    - broadcast packets

											///<    - control and management packets

											///<

											///< When monitor mode is off, the device has a filter on unicast packets to capture only the packets whose MAC

											///< destination address equals the device's address. This means the following frames will be received:

											///<   - unicast packets whose destination is the address of the device

											///<   - multicast packets

											///<   - broadcast packets

											///<   - beacons and probe requests
 

#define AIRPCAP_MF_ACK_FRAMES_ON		2	///< If set, the device will acknowledge the data frames sent to its address. This is useful when the device needs to interact with other devices on the 

											///< 802.11 network, bacause handling the ACKs in software is normally too slow.
 

/*@}*/
 

/** @defgroup airpcapfuncs AirPcap functions

 *  @{

 */
 

/*!

  \brief Returns a string with the API version

  \param VersionMajor Pointer to a variable that will be filled with the major version number.

  \param VersionMinor Pointer to a variable that will be filled with the minor version number.

  \param VersionRev Pointer to a variable that will be filled with the revision number.

  \param VersionBuild Pointer to a variable that will be filled with the build number.

*/

void AirpcapGetVersion(PUINT VersionMajor, PUINT VersionMinor, PUINT VersionRev, PUINT VersionBuild);
 

/*!

  \brief Returns the last error related to the specified handle

  \param AdapterHandle Handle to an open adapter.

  \return The string with the last error.

*/

PCHAR AirpcapGetLastError(PAirpcapHandle AdapterHandle);
 

/*! 

  \brief Returns the list of available devices 

  \param PPAllDevs Address to a caller allocated pointer. On success this pointer will receive the head of a list of available devices.

  \param Ebuf String that will contain error information if FALSE is returned. The size of the string must be AIRPCAP_ERRBUF_SIZE bytes.

  \return TRUE on success. FALSE is returned on failure, in which case Ebuf is filled in with an appropriate error message.

  

	Here's a snippet of code that shows how to use AirpcapGetDeviceList():
 

	\code

	CHAR Ebuf[AIRPCAP_ERRBUF_SIZE];

	AirpcapDeviceDescription *Desc, *tDesc;
 

	if(AirpcapGetDeviceList(&Desc, Ebuf) == -1)

	{

		printf("Unable to get the list of devices: %s\n", Ebuf);

		return -1;

	}

	

	for(tDesc = Desc; tDesc; tDesc = tDesc->next)

	{

		printf("%u) %s (%s)\n",

		++i,

		tDesc->Name,

		tDesc->Description);

	}
 

  	AirpcapFreeDeviceList(Desc);

	\endcode

*/

BOOL AirpcapGetDeviceList(PAirpcapDeviceDescription *PPAllDevs, PCHAR Ebuf);
 

/*!

  \brief Frees a list of devices returned by AirpcapGetDeviceList()

  \param PAllDevs Head of the list of devices returned by \ref AirpcapGetDeviceList().

*/

VOID AirpcapFreeDeviceList(PAirpcapDeviceDescription PAllDevs);
 

/*!

  \brief Opens an adapter

  \param DeviceName Name of the device to open. Use \ref AirpcapGetDeviceList() to get the list of devices.

  \param Ebuf String that will contain error information in case of failure. The size of the string must be AIRPCAP_ERRBUF_SIZE bytes.

  \return A PAirpcapHandle handle on success. NULL is returned on failure, in which case Ebuf is filled in with an appropriate error message.

*/

PAirpcapHandle AirpcapOpen(PCHAR DeviceName, PCHAR Ebuf);
 

/*!

  \brief Closes an adapter

  \param AdapterHandle Handle to the adapter to close.

*/

VOID AirpcapClose(PAirpcapHandle AdapterHandle);
 

/*!

  \brief Sets the device's monitor mode and acknowledgment settings.

  \param AdapterHandle Handle to the adapter.

  \param AirpcapMacFlags Flags word, that contains a bitwise-OR combination of the following flags: \ref AIRPCAP_MF_MONITOR_MODE_ON and \ref AIRPCAP_MF_ACK_FRAMES_ON .

  \return TRUE on success.
 

  When an adapter is plugged into the system, it's always configured with monitor mode ON and acknowledgment settings OFF.

		These values are not stored persistently, so if you want to turn monitor mode off, you will need to do it 

		every time you attach the adapter.
 

  \note currently, the AirPcap adapter supports frames acknowleging when the adapter is NOT in monitor mode. This means that

        the combinations in which the two flags have the same value will cause AirpcapSetDeviceMacFlags() to fail.

*/

BOOL AirpcapSetDeviceMacFlags(PAirpcapHandle AdapterHandle, UINT AirpcapMacFlags);
 

/*!

  \brief Gets the device's monitor mode and acknowledgement settings.

  \param AdapterHandle Handle to the adapter.

  \param PAirpcapMacFlags User-provided flags word, that will be filled by the function with an OR combination of the 

         following flags: \ref AIRPCAP_MF_MONITOR_MODE_ON and \ref AIRPCAP_MF_ACK_FRAMES_ON.

  \return TRUE on success.
 

  When an adapter is plugged into the system, it's always configured with monitor mode ON and acknowledgment settings OFF.

		These values are not stored persistently, so if you want to turn monitor mode off, you will need to do it 

		every time you attach the adapter.

*/

BOOL AirpcapGetDeviceMacFlags(PAirpcapHandle AdapterHandle, PUINT PAirpcapMacFlags);
 

/*!

  \brief Sets the link type of an adapter

  \param AdapterHandle Handle to the adapter.

  \param NewLinkType the "link type", i.e. the format of the frames that will be received from the adapter.

  \return TRUE on success.
 

  the "link type" determines how the driver will encode the packets captured from the network.

  Aircap supports two link types:

  - \ref AIRPCAP_LT_802_11, to capture 802.11 frames (including control frames) without any

   power information. Look at the "Capture_no_radio" example application in the developer's pack 

   for a reference on how to decode 802.11 frames with this link type.

  - \ref AIRPCAP_LT_802_11_PLUS_RADIO, to capture 802.11 frames (including control frames) with a radiotap header

  that contains power and channel information. More information about the radiotap header can be found in the

  \ref radiotap section. Moreover, the "Capture_radio" example application in 

  the developer's pack can be used as a reference on how to decode 802.11 frames with radiotap headers.

  - \ref AIRPCAP_LT_802_11_PLUS_PPI, to capture 802.11 frames (including control frames) with a Per Packet Information (PPI)

	header that contains per-packet meta information like channel and power information. More details on the PPI header can

	be found in the PPI online documentation (TODO).

*/

BOOL AirpcapSetLinkType(PAirpcapHandle AdapterHandle, AirpcapLinkType NewLinkType);
 

/*!

  \brief Gets the link type of the specified adapter

  \param AdapterHandle Handle to the adapter.

  \param PLinkType Pointer to a caller allocated AirpcapLinkType variable that will contain the link type of the adapter.

  \return TRUE on success.
 

  the "link type" determines how the driver will encode the packets captured from the network.

  Aircap supports two link types:

  - \ref AIRPCAP_LT_802_11, to capture 802.11 frames (including control frames) without any

   power information. Look at the "Capture_no_radio" example application in the developer's pack 

   for a reference on how to decode 802.11 frames with this link type.

  - \ref AIRPCAP_LT_802_11_PLUS_RADIO, to capture 802.11 frames (including control frames) with a radiotap header

  that contains power and channel information. More information about the radiotap header can be found int the

  \ref radiotap section. Moreover, the "Capture_radio" example application in 

  the developer's pack can be used as a reference on how to decode 802.11 frames with radiotap headers.

  - \ref AIRPCAP_LT_802_11_PLUS_PPI, to capture 802.11 frames (including control frames) with a Per Packet Information (PPI)

	header that contains per-packet meta information like channel and power information. More details on the PPI header can

	be found in the PPI online documentation (TODO).

*/

BOOL AirpcapGetLinkType(PAirpcapHandle AdapterHandle, PAirpcapLinkType PLinkType);
 

/*!

  \brief Configures the adapter on whether to include the MAC Frame Check Sequence in the captured packets.

  \param AdapterHandle Handle to the adapter.

  \param IsFcsPresent TRUE if the packets should include the FCS. FALSE otherwise

  \return TRUE on success.
 

  In the default configuration, the adapter includes the FCS in the captured packets. The MAC Frame Check Sequence 

  is 4 bytes and is located at the end of the 802.11 packet, with \ref AIRPCAP_LT_802_11, \ref AIRPCAP_LT_802_11_PLUS_RADIO and

  \ref AIRPCAP_LT_802_11_PLUS_PPI link types.

  When the FCS inclusion is turned on, and if the link type is \ref AIRPCAP_LT_802_11_PLUS_RADIO, the radiotap header 

  that precedes each frame has two additional fields at the end: Padding and FCS. These two fields are not present 

  when FCS inclusion is off.

*/	

BOOL AirpcapSetFcsPresence(PAirpcapHandle AdapterHandle, BOOL IsFcsPresent);
 

/*!

  \brief Returns TRUE if the specified adapter includes the MAC Frame Check Sequence in the captured packets 

  \param AdapterHandle Handle to the adapter.

  \param PIsFcsPresent User-provided variable that will be set to true if the adapter is including the FCS.

  \return TRUE if the operation is successful. FALSE otherwise.
 

  In the default configuration, the adapter includes the FCS in the captured packets. The MAC Frame Check Sequence 

  is 4 bytes and is located at the end of the 802.11 packet, with \ref AIRPCAP_LT_802_11, \ref AIRPCAP_LT_802_11_PLUS_RADIO and

  \ref AIRPCAP_LT_802_11_PLUS_PPI link types.

  When the FCS inclusion is turned on, and if the link type is \ref AIRPCAP_LT_802_11_PLUS_RADIO, the radiotap header 

  that precedes each frame has two additional fields at the end: Padding and FCS. These two fields are not present 

  when FCS inclusion is off.

*/

BOOL AirpcapGetFcsPresence(PAirpcapHandle AdapterHandle, PBOOL PIsFcsPresent);
 

/*!

  \brief Configures the adapter to accept or drop frames with an incorrect Frame Check sequence (FCS).

  \param AdapterHandle Handle to the adapter.

  \param ValidationType The type of validation the driver will perform. See the documentation of \ref AirpcapValidationType for details.

  \return TRUE on success.
 

  \note By default, the driver is configured in \ref AIRPCAP_VT_ACCEPT_EVERYTHING mode.

*/

BOOL AirpcapSetFcsValidation(PAirpcapHandle AdapterHandle, AirpcapValidationType ValidationType);
 

/*!

  \brief Checks if the specified adapter is configured to capture frames with incorrect an incorrect Frame Check Sequence (FCS). 

  \param AdapterHandle Handle to the adapter.

  \param ValidationType Pointer to a user supplied variable that will contain the type of validation the driver will perform. See the documentation of \ref AirpcapValidationType for details.

  \return TRUE if the operation is succesful. FALSE otherwise.
 

  \note By default, the driver is configured in \ref AIRPCAP_VT_ACCEPT_EVERYTHING mode.

*/

BOOL AirpcapGetFcsValidation(PAirpcapHandle AdapterHandle, PAirpcapValidationType ValidationType);
 

/*!

  \brief Sets the list of decryption keys that AirPcap is going to use with the specified device.

  \param AdapterHandle Handle an open adapter instance.

  \param KeysCollection Pointer to a \ref PAirpcapKeysCollection structure that contains the keys to be set in the device.

  \return TRUE if the operation is successful. FALSE otherwise.
 

  AirPcap is able to use a set of decryption keys to decrypt the traffic transmitted on a specific SSID. If one of the

  keys corresponds to the one the frame has been encrypted with, the driver will perform decryption and return the cleartext frames

  to the application.
 

  This function allows to set the <b>device-specific</b> set of keys. These keys will be used by the specified device only,

  and will not be used by other airpcap devices besides the specified one. 
 

  At this time, the only supported decryption method is WEP.
 

  The keys are applied to the packets in the same order they appear in the KeysCollection structure until the packet is 

  correctly decrypted, therefore putting frequently used keys at the beginning of the structure improves performance.
 

  \note When you change the set of keys from an open capture instance, the change will be

         immediately reflected on all the other capture instances on the same device.

*/

BOOL AirpcapSetDeviceKeys(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection);
 

/*!

  \brief Returns the list of decryption keys that are currently associated with the specified device 

  \param AdapterHandle Handle to an open adapter instance.

  \param KeysCollection User-allocated PAirpcapKeysCollection structure that will be filled with the keys.

  \param PKeysCollectionSize 

							- \b IN: pointer to a user-allocated variable that contains the length of the KeysCollection structure, in bytes.

							- \b OUT: amount of data moved by AirPcap in the buffer pointed by KeysBuffer, in bytes.

  \return TRUE if the operation is successful. If an error occurs, the return value is FALSE and KeysCollectionSize is zero. 

  If the provided buffer is too small to contain the keys, the return value is FALSE and KeysCollectionSize contains the

  needed KeysCollection length, in bytes. If the device doesn't have any decryption key configured, the return value is TRUE, and 

  KeysCollectionSize will be zero.

  

  This function returns the <b>device-specific</b> set of keys. These keys are used by the specified device only,

  and not by other airpcap devices besides the specified one. 
 

  AirPcap is able to use a set of decryption keys to decrypt the traffic transmitted on a specific SSID. If one of the

  keys corresponds to the one the frame has been encrypted with, the driver will perform decryption and return the cleartext frames

  to the application. 

  AirPcap supports, for every device, multiple keys at the same time.
 

  The configured decryption keys are device-specific, therefore AirpcapGetDeviceKeys() will return a different set of keys

  when called on different devices.
 

  At this time, the only supported decryption method is WEP.

*/

BOOL AirpcapGetDeviceKeys(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection, PUINT PKeysCollectionSize);
 

/*!

  \brief Set the global list of decryption keys that AirPcap is going to use with all the devices.

  \param AdapterHandle Handle an open adapter instance.

  \param KeysCollection Pointer to a \ref PAirpcapKeysCollection structure that contains the keys to be set globally.

  \return TRUE if the operation is successful. FALSE otherwise.
 

  The AirPcap driver is able to use a set of decryption keys to decrypt the traffic transmitted on a specific SSID. If one of the

  keys corresponds to the one the frame has been encrypted with, the driver will perform decryption and return the cleartext frames

  to the application.
 

  This function allows to set the <b>global</b> set of keys. These keys will be used by all the devices plugged in

  the machine. 
 

  At this time, the only supported decryption method is WEP.
 

  The keys are applied to the packets in the same order they appear in the KeysCollection structure until the packet is 

  correctly decrypted, therefore putting frequently used keys at the beginning of the structure improves performance.
 

  \note When you change the set of keys from an open capture instance, the change will be

         immediately reflected on all the other capture instances.

*/

BOOL AirpcapSetDriverKeys(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection);
 

/*!

  \brief Returns the global list of decryption keys that AirPcap is using with all the devices.

  \param AdapterHandle Handle to an open adapter instance.

  \param KeysCollection User-allocated PAirpcapKeysCollection structure that will be filled with the keys.

  \param PKeysCollectionSize 

							- \b IN: pointer to a user-allocated variable that contains the length of the KeysCollection structure, in bytes.

							- \b OUT: amount of data moved by AirPcap in the buffer pointed by KeysBuffer, in bytes.

  \return TRUE if the operation is successful. If an error occurs, the return value is FALSE and KeysCollectionSize is zero. 

  If the provided buffer is too small to contain the keys, the return value is FALSE and KeysCollectionSize contains the

  needed KeysCollection length, in bytes. If no global decryption keys are configured, the return value is TRUE, and 

  KeysCollectionSize will be zero.

  

  This function returns the <b>global</b> set of keys. These keys will be used by all the devices plugged in

  the machine. 
 

  The AirPcap driver is able to use a set of decryption keys to decrypt the traffic transmitted on a specific SSID. If one of the

  keys corresponds to the one the frame has been encrypted with, the driver will perform decryption and return the cleartext frames

  to the application.
 

  At this time, the only supported decryption method is WEP.

*/

BOOL AirpcapGetDriverKeys(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection, PUINT PKeysCollectionSize);
 

/*!

  \brief Turns on or off the decryption of the incoming frames with the <b>device-specific</b> keys.

  \param AdapterHandle Handle to the adapter.

  \param Enable Either \ref AIRPCAP_DECRYPTION_ON or \ref AIRPCAP_DECRYPTION_OFF

  \return TRUE on success.
 

  The device-specific decryption keys can be configured with the \ref AirpcapSetDeviceKeys() function.

  \note By default, the driver is configured with \ref AIRPCAP_DECRYPTION_ON.

*/

BOOL AirpcapSetDecryptionState(PAirpcapHandle AdapterHandle, AirpcapDecryptionState Enable);
 

/*!

  \brief Tells if this open instance is configured to perform the decryption of the incoming frames with the <b>device-specific</b> keys.

  \param AdapterHandle Handle to the adapter.

  \param PEnable Pointer to a user supplied variable that will contain the decryption configuration. See \ref PAirpcapDecryptionState for details.

  \return TRUE if the operation is succesful. FALSE otherwise.
 

  The device-specific decryption keys can be configured with the \ref AirpcapSetDeviceKeys() function.

  \note By default, the driver is configured with \ref AIRPCAP_DECRYPTION_ON.

*/

BOOL AirpcapGetDecryptionState(PAirpcapHandle AdapterHandle, PAirpcapDecryptionState PEnable);
 

/*!

  \brief Turns on or off the decryption of the incoming frames with the <b>global</b> set of keys.

  \param AdapterHandle Handle to the adapter.

  \param Enable Either \ref AIRPCAP_DECRYPTION_ON or \ref AIRPCAP_DECRYPTION_OFF

  \return TRUE on success.
 

  The global decryption keys can be configured with the \ref AirpcapSetDriverKeys() function.

  \note By default, the driver is configured with \ref AIRPCAP_DECRYPTION_ON.

*/

BOOL AirpcapSetDriverDecryptionState(PAirpcapHandle AdapterHandle, AirpcapDecryptionState Enable);
 

/*!

  \brief Tells if this open instance is configured to perform the decryption of the incoming frames with the <b>global</b> set of keys.

  \param AdapterHandle Handle to the adapter.

  \param PEnable Pointer to a user supplied variable that will contain the decryption configuration. See \ref PAirpcapDecryptionState for details.

  \return TRUE if the operation is successful. FALSE otherwise.
 

  The global decryption keys can be configured with the \ref AirpcapSetDriverKeys() function.

  \note By default, the driver is configured with \ref AIRPCAP_DECRYPTION_ON.

*/

BOOL AirpcapGetDriverDecryptionState(PAirpcapHandle AdapterHandle, PAirpcapDecryptionState PEnable);
 

/*!

  \brief Sets the radio channel of a device

  \param AdapterHandle Handle to the adapter.

  \param Channel the new channel to set.

  \return TRUE on success.
 

  The list of available channels can be retrieved with \ref AirpcapGetDeviceSupportedChannels(). The default channel setting is 6.
 

  \note This is a device-related function: when you change the channel from an open capture instance, the change will be

         immediately reflected on all the other capture instances.

*/

BOOL AirpcapSetDeviceChannel(PAirpcapHandle AdapterHandle, UINT Channel);
 

/*!

  \brief Gets the radio channel of a device

  \param AdapterHandle Handle to the adapter.

  \param PChannel Pointer to a user-supplied variable into which the function will copy the currently configured radio channel.

  \return TRUE on success.
 

  The list of available channels can be retrieved with \ref AirpcapGetDeviceSupportedChannels(). The default channel setting is 6.
 

  \note This is a device-related function: when you change the channel from an open capture instance, the change will be

         immediately reflected on all the other capture instances.

*/

BOOL AirpcapGetDeviceChannel(PAirpcapHandle AdapterHandle, PUINT PChannel);
 

/*!

  \brief Sets the channel of a device through its radio frequency. In case of 802.11n enabled devices, it sets the extension channel, if used.

  \param AdapterHandle Handle to the adapter.

  \param ChannelInfo The new channel information to set.

  \return TRUE on success.
 

  \note This is a device-related function: when you change the channel from an open capture instance, the change will be

         immediately reflected on all the other capture instances.

*/

BOOL AirpcapSetDeviceChannelEx(PAirpcapHandle AdapterHandle, AirpcapChannelInfo ChannelInfo);
 

/*!

  \brief Gets the channel of a device through its radio frequency. In case of 802.11n enabled devices, it gets the extension channel, if in use.

  \param AdapterHandle Handle to the adapter.

  \param PChannelInfo Pointer to a user-supplied variable into which the function will copy the currently configured channel information.

  \return TRUE on success.
 

  \note This is a device-related function: when you change the channel from an open capture instance, the change will be

         immediately reflected on all the other capture instances.

*/

BOOL AirpcapGetDeviceChannelEx(PAirpcapHandle AdapterHandle, PAirpcapChannelInfo PChannelInfo);
 

/*!

  \brief Gets the list of supported channels for a given device. In case of a 802.11n capable device, information related to supported extension channels is also reported. 
 

  Every control channel is listed multiple times, one for each different supported extension channel. For example channel 6 (2437MHz)  is usually listed three times:

	- <b>Frequency 2437 Extension +1</b>. Control channel is 6, extension channel is 10.

	- <b>Frequency 2437 Extension 0</b>. Control channel is 6, no extension channel is used (20MHz channel and legacy mode).

	- <b>Frequency 2437 Extension -1</b>. Control channel is 6, extension channel is 2.

  \param AdapterHandle Handle to the adapter.

  \param ppChannelInfo Pointer to a user-supplied variable that will point to an array of supported channel. Such list must not be freed by the caller

  \param pNumChannelInfo Number of channels returned in the array.

  \return TRUE on success.
 

  \note The supported channels are not listed in any specific order.

*/

BOOL AirpcapGetDeviceSupportedChannels(PAirpcapHandle AdapterHandle, PAirpcapChannelInfo *ppChannelInfo, PUINT pNumChannelInfo);
 

/*!

  \brief Converts a given frequency to the corresponding channel.
 

  \param Frequency Frequency of the channel, in MHz.

  \param PChannel Pointer to a user-supplied variable that will contain the channel number on success.

  \param PBand Pointer to a user-supplied variable that will contain the band (a or b/g) of the given channel.

  \return TRUE on success, i.e. the frequency corresponds to a valid a or b/g channel.

*/

BOOL AirpcapConvertFrequencyToChannel(UINT Frequency, PUINT PChannel, PAirpcapChannelBand PBand);
 

/*!

  \brief Converts a given channel to the corresponding frequency.
 

  \param Channel Channel number to be converted.

  \param PFrequency Pointer to a user-supplied variable that will contain the channel frequency in MHz on success.

  \return TRUE on success, i.e. the given channel number exists.

*/

BOOL AirpcapConvertChannelToFrequency(UINT Channel, PUINT PFrequency);
 

/*!

  \brief Sets the size of the kernel packet buffer for this adapter

  \param AdapterHandle Handle to the adapter.

  \param BufferSize New size, in bytes.

  \return TRUE on success.
 

  Every AirPcap open instance has an associated kernel buffer, whose default size is 1 Mbyte.

  This function can be used to change the size of this buffer, and can be called at any time.

  A bigger kernel buffer size decreases the risk of dropping packets during network bursts or when the

  application is busy, at the cost of higher kernel memory usage.
 

  \note Don't use this function unless you know what you are doing. Due to caching issues and bigger non-paged

  memory consumption, bigger buffer sizes can decrease the capture performace instead of improving it.

*/

BOOL AirpcapSetKernelBuffer(PAirpcapHandle AdapterHandle, UINT BufferSize);
 

/*!

  \brief Gets the size of the kernel packet buffer for this adapter

  \param AdapterHandle Handle to the adapter.

  \param PSizeBytes User-allocated variable that will be filled with the size of the kernel buffer.

  \return TRUE on success.
 

  Every AirPcap open instance has an associated kernel buffer, whose default size is 1 Mbyte.

  This function can be used to get the size of this buffer.

*/

BOOL AirpcapGetKernelBufferSize(PAirpcapHandle AdapterHandle, PUINT PSizeBytes);
 

/*!

  \brief Saves the configuration of the specified adapter in the registry, so that it becomes the default for this adapter.

  \param AdapterHandle Handle to the adapter.

  \return TRUE on success. FALSE on failure.
 

  Almost all the AirPcap calls that modify the configuration (\ref AirpcapSetLinkType(), \ref AirpcapSetFcsPresence(), 

  \ref AirpcapSetFcsValidation(), \ref AirpcapSetKernelBuffer(), \ref AirpcapSetMinToCopy())

  affect only the referenced AirPcap open instance. This means that if you do another \ref AirpcapOpen() on the same

  adapter, the configuration changes will not be remembered, and the new adapter handle will have default configuration

  settings.
 

  Exceptions to this rule are the \ref AirpcapSetDeviceChannel() and \ref AirpcapSetDeviceKeys() functions: a channel change is 

  reflected on all the open instances, and remembered until the next call to \ref AirpcapSetDeviceChannel(), until the adapter 

  is unplugged, or until the machine is powered off. Same thing for the configuration of the WEP keys.
 

  AirpcapStoreCurConfigAsAdapterDefault() stores the configuration of the give open instance as the default for the adapter: 

  all the instances opened in the future will have the same configuration that this adapter currently has.

  The configuration is stored in the registry, therefore it is remembered even when the adapter is unplugged or the

  machine is turned off. However, an adapter doesn't bring its configuration with it from machine to machine.
 

  the configuration information saved in the registry includes the following parameters:

   - channel

   - kernel buffer size

   - mintocopy

   - link type

   - CRC presence

   - Encryption keys

   - Encryption Enabled/Disabled state
 

  The configuration is device-specific. This means that changing the configuration of a device

  doesn't modify the one of the other devices that are currently used or that will be used in the future.
 

  \note AirpcapStoreCurConfigAsAdapterDefault() must have exclusive access to the adapter -- it 

   will fail if more than one AirPcap handle is opened at the same time for this device. 

   AirpcapStoreCurConfigAsAdapterDefault() needs administrator privileges. It will fail if the calling user

   is not a local machine administrator.

*/

BOOL AirpcapStoreCurConfigAsAdapterDefault(PAirpcapHandle AdapterHandle);
 

/*!

  \brief Sets the BPF kernel filter for an adapter

  \param AdapterHandle Handle to the adapter.

  \param Instructions pointer to the first BPF instruction in the array. Corresponds to the  bf_insns 

   in a bpf_program structure (see the WinPcap documentation at http://www.winpcap.org/devel.htm).

  \param Len Number of instructions in the array pointed by the previous field. Corresponds to the bf_len in

  a a bpf_program structure (see the WinPcap documentation at http://www.winpcap.org/devel.htm).

  \return TRUE on success.
 

  The AirPcap driver is able to perform kernel-level filtering using the standard BPF pseudo-machine format. You can read

  the WinPcap documentation at http://www.winpcap.org/devel.htm for more details on the BPF filtering mechaism.
 

  A filter can be automatically created by using the pcap_compile() function of the WinPcap API. This function 

  converts a human readable text expression with the tcpdump/libpcap syntax into a BPF program. 

  If your program doesn't link wpcap, but you need to generate the code for a particular filter, you can run WinDump 

  with the -d or -dd or -ddd flags to obtain the pseudocode.
 

*/

BOOL AirpcapSetFilter(PAirpcapHandle AdapterHandle, PVOID Instructions, UINT Len);
 

/*!

  \brief Returns the MAC address of a device.

  \param AdapterHandle Handle to the adapter.

  \param PMacAddress Pointer to a user allocated \ref AirpcapMacAddress structure that will receive the MAC address on success. 

  \return TRUE on success.

*/

BOOL AirpcapGetMacAddress(PAirpcapHandle AdapterHandle, PAirpcapMacAddress PMacAddress);
 

/*!

  \brief Sets the MAC address of a device.

  \param AdapterHandle Handle to the adapter.

  \param PMacAddress Pointer to a user-initialized structure containing the MAC address.

  \return TRUE on success. FALSE on failure, or if the adapter doesn't support changing the address.
 

  Using this function, the programmer can change the MAC address of the device. This is useful when disabling monitor

  mode with \ref AirpcapSetDeviceMacFlags(), because the device will acknowledge the data frames sent to its MAC address.

  

  \note The address change is temporary: when the device is unplugged or when the host PC is turned off, the address is reset to the original

  value.

*/

BOOL AirpcapSetMacAddress(PAirpcapHandle AdapterHandle, PAirpcapMacAddress PMacAddress);
 

/*!

  \brief Sets the mintocopy parameter for an open adapter.

  \param AdapterHandle Handle to the adapter.

  \param MinToCopy is the mintocopy size in bytes.

  \return TRUE on success.
 

  When the number of bytes in the kernel buffer changes from less than mintocopy bytes to greater than or equal to mintocopy bytes, 

  the read event is signalled (see \ref AirpcapGetReadEvent()). A high value for mintocopy results in poor responsiveness since the

  driver may signal the application "long" after the arrival of the packet. And a high value results in low CPU loading

  by minimizing the number of user/kernel context switches. 

  A low MinToCopy results in good responsiveness since the driver will signal the application close to the arrival time of

  the packet. This has higher CPU loading over the first approach.

*/

BOOL AirpcapSetMinToCopy(PAirpcapHandle AdapterHandle, UINT MinToCopy);
 

/*!

  \brief Gets an event that is signalled when packets are available in the kernel buffer (see \ref AirpcapSetMinToCopy()).

  \param AdapterHandle Handle to the adapter.

  \param PReadEvent Pointer to a user-supplied handle in which the read event will be copied.

  \return TRUE on success.
 

  \note The event is signalled when at least mintocopy bytes are present in the kernel buffer (see \ref AirpcapSetMinToCopy()). 

  This event can be used by WaitForSingleObject() and WaitForMultipleObjects() to create blocking behavior when reading 

  packets from one or more adapters (see \ref AirpcapRead()).

*/

BOOL AirpcapGetReadEvent(PAirpcapHandle AdapterHandle, HANDLE* PReadEvent);
 

/*!

  \brief Fills a user-provided buffer with zero or more packets that have been captured on the referenced adapter.

  \param AdapterHandle Handle to the adapter.

  \param Buffer pointer to the buffer that will be filled with captured packets.

  \param BufSize size of the input buffer that will contain the packets, in bytes.

  \param PReceievedBytes Pointer to a user supplied variable that will receive the number of bytes copied by AirpcapRead. 

  Can be smaller than BufSize.

  \return TRUE on success.
 

  802.11 frames are returned by the driver in buffers. Every 802.11 frame in the buffer is preceded by a \ref AirpcapBpfHeader structure.

  The suggested way to use an AirPcap adapter is through the pcap API exported by wpcap.dll. If this is not

  possible, the Capture_radio and Capture_no_radio examples in the AirPcap developer's pack show how to properly decode the 

  packets in the read buffer returned by AirpcapRead().
 

  \note This function is NOT blocking. Blocking behavior can be obtained using the event returned

   by \ref AirpcapGetReadEvent(). See also \ref AirpcapSetMinToCopy().

*/

BOOL AirpcapRead(PAirpcapHandle AdapterHandle, PBYTE Buffer, UINT BufSize, PUINT PReceievedBytes);
 

/*!

  \brief Transmits a packet.

  \param AdapterHandle Handle to the adapter.

  \param TxPacket Pointer to a buffer that contains the packet to be transmitted.

  \param PacketLen Length of the buffer pointed by the TxPacket argument, in bytes.

  \return TRUE on success.
 

  The packet will be transmitted on the channel the device is currently set. To change the device adapter, use the 

  \ref AirpcapSetDeviceChannel() function.
 

  If the link type of the adapter is AIRPCAP_LT_802_11, the buffer pointed by TxPacket should contain just the 802.11

  packet, without additional information. The packet will be transmitted at 1Mbps.
 

  If the link type of the adapter is AIRPCAP_LT_802_11_PLUS_RADIO, the buffer pointed by TxPacket should contain a radiotap

  header followed by the 802.11 packet. AirpcapWrite will use the rate information in the radiotap header when

  transmitting the packet.

  

  If the link type of the adapter is AIRPCAP_LT_802_11_PLUS_PPI, ????? TODO ????

*/

BOOL AirpcapWrite(PAirpcapHandle AdapterHandle, PCHAR TxPacket, ULONG PacketLen);
 

/*!

  \brief Gets per-adapter WinPcap-compatible capture statistics.

  \param AdapterHandle Handle to the adapter.

  \param PStats pointer to a user-allocated AirpcapStats structure that will be filled with statistical information.

  \return TRUE on success.

*/

BOOL AirpcapGetStats(PAirpcapHandle AdapterHandle, PAirpcapStats PStats);
 

/*!

  \brief Gets the number of LEDs the referenced adapter has available.

  \param AdapterHandle Handle to the adapter.

  \param NumberOfLeds Number of LEDs available on this adapter.

  \return TRUE on success.

*/

BOOL AirpcapGetLedsNumber(PAirpcapHandle AdapterHandle, PUINT NumberOfLeds);
 

/*!

  \brief Turns on one of the adapter's LEDs.

  \param AdapterHandle Handle to the adapter.

  \param LedNumber zero-based identifier of the LED to turn on.

  \return TRUE on success.

*/

BOOL AirpcapTurnLedOn(PAirpcapHandle AdapterHandle, UINT LedNumber);
 

/*!

  \brief Turns off one of the adapter's LEDs.

  \param AdapterHandle Handle to the adapter.

  \param LedNumber zero-based identifier of the LED to turn off.

  \return TRUE on success.

*/

BOOL AirpcapTurnLedOff(PAirpcapHandle AdapterHandle, UINT LedNumber);
 

/*@}*/
 

#endif // __AIRPCAP_DRIVER__
 

#ifdef __cplusplus

}

#endif
 

#endif // !defined(AIRPCAP_H__EAE405F5_0171_9592_B3C2_C19EC426AD34__INCLUDED_)

Open in new window

0
Comment
Question by:mileyja
  • 33
  • 15
  • 3
51 Comments
 
LVL 55

Expert Comment

by:Jaime Olivares
ID: 20346919
do you have an specific question?
0
 

Author Comment

by:mileyja
ID: 20346938
sorry, i want the c function above "AirpcapOpen" (not in the snippet but in the actual question, along with the structure of the return type) wrapped in c# using a dllimport, if you can give it back to me in c# and/or in vb.net that would be great.
0
 

Author Comment

by:mileyja
ID: 20346959
preferably c# at this point, also there is more info on the function i had wrapped in c# before it at http://www.experts-exchange.com/Programming/Languages/.NET/Visual_Basic.NET/Q_22976921.html
0
 
LVL 55

Expert Comment

by:Jaime Olivares
ID: 20347059
did you translate the AircapHandle struct?

appears you need something like:
<DllImport("airpcap.dll", EntryPoint:="AirpcapOpen", CharSet:=CharSet.Ansi)> _
Private Shared Function AirpcapOpen(ByRef DeviceName as String, ByRef Ebuf as String) as IntPtr

this will return a pointer, then dereference the IntPtr with Marshal.PtrToStructure()
0
 
LVL 55

Expert Comment

by:Jaime Olivares
ID: 20347082
in C#:

[DllImport("airpcap.dll", EntryPoint="AirpcapOpen", CharSet=CharSet.Ansi)]
private static IntPtr AirpcapOpen(string DeviceName, string Ebuf);

0
 

Author Comment

by:mileyja
ID: 20347127
No i have not translated the structure, how would that work??
0
 
LVL 55

Expert Comment

by:Jaime Olivares
ID: 20347175
it should be something like:

struct _AirpcapHandle
{
      public UInt32 OsHandle;                  
      public UInt32 ReadEvent;
      public UInt32 Flags;      // Currently unused
      public AIRPCAP_ADAPTER_TYPE AdapterType;
      public UInt32 hKey;
      public IntPtr pChannels;  //  AirpcapChannelInfo *
      public ULong NumChannels;
      [MarshalAs(UnmanagedType.ByValTStr, SizeConst=512)]
      public string Ebuf;
};
0
 

Author Comment

by:mileyja
ID: 20347256
it doesnt know what ulong or AIRPCAP_ADAPTER_TYPE is ?  I think we might be close there though.
0
 
LVL 55

Expert Comment

by:Jaime Olivares
ID: 20347337
Sorry, replace ULong with UInt64

struct _AirpcapHandle
{
      public UInt32 OsHandle;                  
      public UInt32 ReadEvent;
      public UInt32 Flags;      // Currently unused
      public AIRPCAP_ADAPTER_TYPE AdapterType;
      public UInt32 hKey;
      public IntPtr pChannels;  //  AirpcapChannelInfo *
      public UInt64 NumChannels;
      [MarshalAs(UnmanagedType.ByValTStr, SizeConst=512)]
      public string Ebuf;
};

about the AIRCAP_ADAPTER_TYPE, you have to declare too, but it is not present in the information you have posted.



0
 

Author Comment

by:mileyja
ID: 20347349
ok it was also in the c file not the header it looks like this, or I think this is what you need

typedef enum _AIRPCAP_ADAPTER_TYPE
{
      ADAPTER_TYPE_AIRPCAP_DRIVER      = 0,
      ADAPTER_TYPE_AR5416_DRIVER      = 1,
}
0
 

Author Comment

by:mileyja
ID: 20347378
it looks like it is used in the code for the AirpcapOpen function

#ifdef HAVE_AR5416_SUPPORT
      AIRPCAP_ADAPTER_TYPE AdapterType = ADAPTER_TYPE_AIRPCAP_DRIVER;

any help??

0
 
LVL 55

Expert Comment

by:Jaime Olivares
ID: 20347382
try to declare previously as:

enum AIRPCAP_ADAPTER_TYPE : UInt32
{
      ADAPTER_TYPE_AIRPCAP_DRIVER      = 0,
      ADAPTER_TYPE_AR5416_DRIVER      = 1
}
0
 

Author Comment

by:mileyja
ID: 20347752
ok here is what I have and I am getting an error that says:  "Method's type signature is not PInvoke compatible."

IN THE CODE SNIPPET IS EXACTLY WHAT i AM TRYING TO DO WITH THIS

I don't think the current issues is with "ah",  I can take it out and get the same error!!


Thoughts??
 struct AirpcapHandle

        {

            public UInt32 OsHandle;

            public UInt32 ReadEvent;

            public UInt32 Flags;      // Currently unused

            public AIRPCAP_ADAPTER_TYPE AdapterType;

            public UInt32 hKey;

            public IntPtr pChannels;  //  AirpcapChannelInfo *

            public ulong NumChannels;

            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 512)]

            public string Ebuf;

        }
 

        [DllImport("airpcap.dll", EntryPoint = "AirpcapOpen", CharSet = CharSet.Ansi)]

        private extern static unsafe AirpcapHandle AirpcapOpen(string DeviceName, ref char* Ebuf);
 

        enum AIRPCAP_ADAPTER_TYPE : uint

        {

            ADAPTER_TYPE_AIRPCAP_DRIVER = 0,

            ADAPTER_TYPE_AR5416_DRIVER = 1

        }
 
 
 
 

        private unsafe void Form1_Load(object sender, EventArgs e)

        {

            string strFoundName = "";

            string strFoundDesc = "";
 

        
 

                char* pErrorBuffer = stackalloc char[513];
 

                AirpcapHandle ah;
 
 
 

               ah = AirpcapOpen(strFoundName, ref pErrorBuffer);
 
 

            }

Open in new window

0
 
LVL 55

Expert Comment

by:Jaime Olivares
ID: 20347771
This looks strange:
[DllImport("airpcap.dll", EntryPoint = "AirpcapOpen", CharSet = CharSet.Ansi)]
private extern static unsafe AirpcapHandle AirpcapOpen(string DeviceName, ref char* Ebuf);
 
it should be:
[DllImport("airpcap.dll", EntryPoint = "AirpcapOpen", CharSet = CharSet.Ansi)]
private extern static unsafe AirpcapHandle AirpcapOpen(string DeviceName, string Ebuf);
 
0
 

Author Comment

by:mileyja
ID: 20347826
This worked for me before on the last function I figured out.

[DllImport("airpcap.dll")]
        private extern static unsafe int AirpcapGetDeviceList(APCDeviceDescription** ppDevices, char* pBuf);

this is an example of something I did before in the previous function I cracked "as an ebuf".  I'll include the code that worked for that just as an idea.  You can see what Wizrr did in the last thread to get the last function to work at http://www.experts-exchange.com/Programming/Languages/.NET/Visual_Basic.NET/Q_22976921.html

Hopefully that will help
0
 
LVL 55

Expert Comment

by:Jaime Olivares
ID: 20347851
it doesn't need to be declared as unsafe, will make your code more complex and "unsafe". it could be simply as I described earlier:
DllImport("airpcap.dll", EntryPoint = "AirpcapOpen", CharSet = CharSet.Ansi)]
private extern static IntPtr AirpcapOpen(string DeviceName, string Ebuf);  
0
 

Author Comment

by:mileyja
ID: 20347868
Below is what I tried in light of what you suggested.

A couple things.  don't you have to pass by ref to get the error buffer back in the end?

The function returns the value as an AirpcapHandle, how does that relate to IntPtr??

In my code I tried to change it.

If I use AirpcapHandle I get "Method's type signature is not PInvoke compatible."

using your way with the above dllimport statement along with

 IntPtr ah;

 ah = AirpcapOpen(strFoundName, pErrorBuffer);

I do not get an error, but I don't know how that translates into the AirpcapHandle structure described earlier




        struct AirpcapHandle

        {

            public UInt32 OsHandle;

            public UInt32 ReadEvent;

            public UInt32 Flags;      // Currently unused

            public AIRPCAP_ADAPTER_TYPE AdapterType;

            public UInt32 hKey;

            public IntPtr pChannels;  //  AirpcapChannelInfo *

            public ulong NumChannels;

            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 512)]

            public string Ebuf;

        }
 

        [DllImport("airpcap.dll", EntryPoint = "AirpcapOpen", CharSet = CharSet.Ansi)]

        private extern static AirpcapHandle AirpcapOpen(string DeviceName, string Ebuf); 
 

        enum AIRPCAP_ADAPTER_TYPE : uint

        {

            ADAPTER_TYPE_AIRPCAP_DRIVER = 0,

            ADAPTER_TYPE_AR5416_DRIVER = 1

        }
 
 
 
 

        private unsafe void Form1_Load(object sender, EventArgs e)

        {

            string strFoundName = "";

            string strFoundDesc = "";
 
 
 

            string pErrorBuffer = "";
 

            AirpcapHandle ah;
 
 
 

            ah = AirpcapOpen(strFoundName, pErrorBuffer);
 
 

        }

        }

    }

Open in new window

0
 

Author Comment

by:mileyja
ID: 20347896
also ignore the extra two brackets at the end of the snippet
0
 
LVL 55

Assisted Solution

by:Jaime Olivares
Jaime Olivares earned 250 total points
ID: 20347913
notice that the function doesn't return a struct, it returns a POINTER to a struct.
That's why I put an IntPtr.
If you want to convert the pointer to a struct, use Marshal.PtrToStructure() as I early suggested:

IntPtr IP = AirpcapOpen("some device name", somestring);  
AirpcapHandle AH = new AirpcapHandle();
Marshal.PtrToStructure(AH, IP);

now you can use AH.

But I have noticed the second argument in AircapOpen is an output buffer, so the proper declaration will be:
DllImport("airpcap.dll", EntryPoint = "AirpcapOpen", CharSet = CharSet.Ansi)]
private extern static IntPtr AirpcapOpen(string DeviceName, StringBuilder Ebuf);

so you can use as:
StringBuffer sb = new StringBuilder(512);  // size = AIRPCAP_ERRBUF_SIZE = 512
IntPtr IP = AirpcapOpen("some device name", sb);  
AirpcapHandle AH = new AirpcapHandle();
Marshal.PtrToStructure(AH, IP);

0
 

Author Comment

by:mileyja
ID: 20347951
what is a stringbuffer, what do i have to include to get it
0
 
LVL 55

Expert Comment

by:Jaime Olivares
ID: 20347959
it is StringBuilder, not stringbuffer, it is a specialized string class, that can grow with easy, and reserve space before it is used.
To use it, you need to write at the top of your C# file:
using Sytem.Text;
0
 

Author Comment

by:mileyja
ID: 20347975
I figured that last one out before your reply.  :)   I think the whole thing is returning null.  

Below (in the snippet)  is what I am trying to do.

Does this help at all on the line:

  Marshal.PtrToStructure(IP, AH);  

I get:  


Value cannot be null.
Parameter name: ptr




 [DllImport("airpcap.dll", EntryPoint = "AirpcapOpen", CharSet = CharSet.Ansi)]

        private extern static IntPtr AirpcapOpen(string DeviceName, StringBuilder Ebuf); 
 

        enum AIRPCAP_ADAPTER_TYPE : uint

        {

            ADAPTER_TYPE_AIRPCAP_DRIVER = 0,

            ADAPTER_TYPE_AR5416_DRIVER = 1

        }
 
 
 
 

        private unsafe void Form1_Load(object sender, EventArgs e)

        {

            string strFoundName = "";

            string strFoundDesc = "";
 
 
 

            string pErrorBuffer = "";
 

         
 

           StringBuilder sb = new StringBuilder(512);  // size = AIRPCAP_ERRBUF_SIZE = 512

           IntPtr IP = new IntPtr();
 

         IP = AirpcapOpen(strFoundName, sb);

       

           AirpcapHandle AH = new AirpcapHandle();

           Marshal.PtrToStructure(IP, AH);
 
 

          

        }

Open in new window

0
 

Author Comment

by:mileyja
ID: 20347979
I feel like we are pretty close, maybe a problem with the way the structure is formed or something small.
0
 
LVL 55

Expert Comment

by:Jaime Olivares
ID: 20347989
ok, you need some "guard":

StringBuffer sb = new StringBuilder(512);  // size = AIRPCAP_ERRBUF_SIZE = 512
IntPtr IP = AirpcapOpen("some device name", sb);  

if (IP != IntPtr.Zero)   // prevent null pointer
{
      AirpcapHandle AH = new AirpcapHandle();
      Marshal.PtrToStructure(AH, IP);
}
else
{
      System.Windows.Forms.MessageBox.Show(sb);   // show error message
}
0
 

Author Comment

by:mileyja
ID: 20348018
ok we are close, really close, the pointer pushes a reference but something is goofy wiht the structure I think MAYBE..

below (in the snippit) is what I am doing.

I had to add a to string to the messagebox line so it reads: System.Windows.Forms.MessageBox.Show(sb.ToString());
otherwise this threw an exception

That line doesn't fire because a valid memory address comes back,

on line : Marshal.PtrToStructure(IP, AH);

I get this exception:  The structure must not be a value class. Parameter name: structure

Any thoughts
        struct AirpcapHandle

        {

            public UInt32 OsHandle;

            public UInt32 ReadEvent;

            public UInt32 Flags;      // Currently unused

            public AIRPCAP_ADAPTER_TYPE AdapterType;

            public UInt32 hKey;

            public IntPtr pChannels;  //  AirpcapChannelInfo *

            public ulong NumChannels;

            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 512)]

            public string Ebuf;

        }
 

        [DllImport("airpcap.dll", EntryPoint = "AirpcapOpen", CharSet = CharSet.Ansi)]

        private extern static IntPtr AirpcapOpen(string DeviceName, StringBuilder Ebuf); 
 

        enum AIRPCAP_ADAPTER_TYPE : uint

        {

            ADAPTER_TYPE_AIRPCAP_DRIVER = 0,

            ADAPTER_TYPE_AR5416_DRIVER = 1

        }
 
 
 
 

        private unsafe void Form1_Load(object sender, EventArgs e)

        {

            string strFoundName = "";

            string strFoundDesc = "";
 

            AirpcapInterface.APCDevice[] devs;

            string outerror = "";

            AirpcapInterface.APCDevice dev;
 

            AirpcapInterface.AirpcapGetDeviceListWrap(out devs, ref outerror);
 

            foreach (AirpcapInterface.APCDevice i in devs)

            {

                strFoundName = i.name;

                strFoundDesc = i.description;
 

            }
 
 

            string pErrorBuffer = "";
 

         
 

           StringBuilder sb = new StringBuilder(512);  // size = AIRPCAP_ERRBUF_SIZE = 512

           IntPtr IP = new IntPtr();
 

         IP = AirpcapOpen(strFoundName, sb);
 

         if (IP != IntPtr.Zero)   // prevent null pointer

         {

             AirpcapHandle AH = new AirpcapHandle();

             Marshal.PtrToStructure(IP, AH);

         }

         else

         {

             System.Windows.Forms.MessageBox.Show(sb.ToString());   // show error message

         }

Open in new window

0
What Is Threat Intelligence?

Threat intelligence is often discussed, but rarely understood. Starting with a precise definition, along with clear business goals, is essential.

 
LVL 55

Assisted Solution

by:Jaime Olivares
Jaime Olivares earned 250 total points
ID: 20348051
ok, better you use a different Marshal version:

if (IP != IntPtr.Zero)   // prevent null pointer

{

        AirpcapHandle AH = (AirpcapHandle)Marshal.PtrToStructure(IP, typeof(AirpcapHandle));

}

else

{

        System.Windows.Forms.MessageBox.Show(sb.ToString());   // show error message

}

Open in new window

0
 
LVL 3

Expert Comment

by:wizrr
ID: 20348096
jaime_olivares is right. there is no need to use unsafe code. Maybe he can help with calling AirpcapGetDevicesList without using unsafe code - so mileyja after that can use it in VB).
0
 

Author Comment

by:mileyja
ID: 20348100
The overall goal to test whether this function works is to use it by passing the adapterhandle to another simpler function to get something back and see if it works

It populates but I urge you to take a look at that adapterhandle structure again, while it seems to populate values, it throws an access violation when i try to use this:

AirpcapTurnLedOff(AH, 1);

    [DllImport("airpcap.dll", EntryPoint = "AirpcapTurnLedOff", CharSet = CharSet.Ansi)]
        private extern static bool AirpcapTurnLedOff(AirpcapHandle ah, uint lednum);

after what we just did

here is what the function looks like

BOOL AirpcapTurnLedOff(PAirpcapHandle AdapterHandle, UINT LedNumber)
{
      DWORD BytesReturned;

#ifdef HAVE_AR5416_SUPPORT
      if (AdapterHandle->AdapterType == ADAPTER_TYPE_AR5416_DRIVER)
      {
            if(DeviceIoControl(AdapterHandle->OsHandle, ATH_CAP_IOCTL_TURNLEDOFF, &LedNumber, sizeof(LedNumber),
                  NULL, 0,
                  &BytesReturned, NULL) == FALSE)
            {
                  _snprintf(AdapterHandle->Ebuf, AIRPCAP_ERRBUF_SIZE, "IOCTL failed: %d\n", GetLastError());
                  return FALSE;
            }

            return TRUE;
      }
#endif

      if(LedNumber != 0)
      {
            return FALSE;
      }

      if(DeviceIoControl(AdapterHandle->OsHandle, IOCTL_TURNLEDOFF, NULL, 0,
            NULL, 0,
            &BytesReturned, NULL) == FALSE)
      {
            _snprintf(AdapterHandle->Ebuf, AIRPCAP_ERRBUF_SIZE, "IOCTL failed: %d\n", GetLastError());
            return FALSE;
      }

      return TRUE;
}
0
 

Author Comment

by:mileyja
ID: 20348113
if there isn't much of a hit I have no problem with just referencing the C# project in vb.net

any thoughts there?

Also, How about that structure and looking at the code i just posted to see why I cannot get this turnledoff function to work after the AdapterHandle structure appears to populate
0
 
LVL 55

Expert Comment

by:Jaime Olivares
ID: 20348124
So, please tell me first if the pointer is different than IntPtr.Zero
0
 

Author Comment

by:mileyja
ID: 20348142
IP is equal to 63324864

the values for AH struct come out from the marshal to

adapter type = GetDeviceList2.Form1.AIRPCAP_ADAPTER_TYPE.ADAPTER_TYPE_AIRPCAP_DRIVER
ebuf = "ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍýýý"
flags = 3452816845
hkey = 4294967295
numchannels = 14829735428352901134
oshandle = 976
pchannels = 63325448 but there is stuff under that, with static members of size 4, whatever that means
read event = 980
0
 

Author Comment

by:mileyja
ID: 20348147
so yes it is different
0
 
LVL 3

Accepted Solution

by:
wizrr earned 250 total points
ID: 20348150
Your mistakes:
Let's see:
BOOL AirpcapTurnLedOff(PAirpcapHandle AdapterHandle, UINT LedNumber)

BOOL is not C# bool. BOOL is int.
PAirpcapHandle is not AirpcapHandle. PAirpcapHandle is AirpcapHandle* or IntPtr.

So the right pinvoke is:
[DllImport("airpcap.dll", EntryPoint = "AirpcapTurnLedOff", CharSet = CharSet.Ansi)]
private extern static int AirpcapTurnLedOff(IntPtr ah, uint lednum);
//
AirpcapHandle handle = ...;
IntPtr pnt = Marshal.AllocHGlobal(Marshal.SizeOf(p));
Marshal.StructureToPtr(handle, pnt, false);
AirpcapTurnLedOff(pnt, 0);
//
dont forget to call Marshal.FreeHGlobal(pnt) to free memory.

Or this
[DllImport("airpcap.dll", EntryPoint = "AirpcapTurnLedOff", CharSet = CharSet.Ansi)]
private extern static int AirpcapTurnLedOff([In, MarshalAs(UnmanagedType.LPStruct)]AirpcapHandle ah, uint lednum);
AirpcapTurnLedOff(handle, 0);

Good luck. You have to learn and do something by your own hands.
0
 

Author Comment

by:mileyja
ID: 20348163
so your saying you don't want to help anymore... it seems, I don't now how i would know that you would have to turn it back into a pointer in order to make it work... Im almost there, after I get this one, the rest of it I can do.  I just need help through getting the leds to turn off and on.  then I can figure out the rest.
0
 

Author Comment

by:mileyja
ID: 20348168
and yes ill make mistakes, Ive never had to work with c# or c in my life.  I put "beginner" in there, i am seeing things all the time you guys are putting in that there is no way I could just know.  After we get the LEDS to to go on and off Im good to go.  Come on, hang in with me for just a bit
0
 
LVL 3

Expert Comment

by:wizrr
ID: 20348174
Sorry but i can't help you right now (i need to go). AirpcapTurnLedOff pinvoke i put in previous message should work. Did you tried it?
0
 

Author Comment

by:mileyja
ID: 20348177
can you put that correct code in the context of what I last used

below is what I did before


        struct AirpcapHandle

        {

            public UInt32 OsHandle;

            public UInt32 ReadEvent;

            public UInt32 Flags;      // Currently unused

            public AIRPCAP_ADAPTER_TYPE AdapterType;

            public UInt32 hKey;

            public IntPtr pChannels;  //  AirpcapChannelInfo *

            public ulong NumChannels;

            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 512)]

            public string Ebuf;

        }
 

        [DllImport("airpcap.dll", EntryPoint = "AirpcapOpen", CharSet = CharSet.Ansi)]

        private extern static IntPtr AirpcapOpen(string DeviceName, StringBuilder Ebuf);
 

        [DllImport("airpcap.dll", EntryPoint = "AirpcapTurnLedOn", CharSet = CharSet.Ansi)]

        private extern static int AirpcapTurnLedOn(IntPtr ah, uint lednum); 
 

        enum AIRPCAP_ADAPTER_TYPE : uint

        {

            ADAPTER_TYPE_AIRPCAP_DRIVER = 0,

            ADAPTER_TYPE_AR5416_DRIVER = 1

        }
 
 
 
 

        private unsafe void Form1_Load(object sender, EventArgs e)

        {

            string strFoundName = "";

            string strFoundDesc = "";
 

            AirpcapInterface.APCDevice[] devs;

            string outerror = "";

            AirpcapInterface.APCDevice dev;
 

            AirpcapInterface.AirpcapGetDeviceListWrap(out devs, ref outerror);
 

            foreach (AirpcapInterface.APCDevice i in devs)

            {

                strFoundName = i.name;

                strFoundDesc = i.description;
 

            }
 
 

            string pErrorBuffer = "";
 

         
 

           StringBuilder sb = new StringBuilder(512);  // size = AIRPCAP_ERRBUF_SIZE = 512

           IntPtr IP = new IntPtr();
 

         IP = AirpcapOpen(strFoundName, sb);

         AirpcapHandle AH = new AirpcapHandle();

         if (IP != IntPtr.Zero)   // prevent null pointer

         {

              AH = (AirpcapHandle)Marshal.PtrToStructure(IP, typeof(AirpcapHandle));

         }

         else

         {

             System.Windows.Forms.MessageBox.Show(sb.ToString());   // show error message

         }
 

           

         AirpcapTurnLedOn(AH, 2);

Open in new window

0
 

Author Comment

by:mileyja
ID: 20348179
all i need is in the context of my program, you used ...'s and such before, I don't know whta that means
0
 

Author Comment

by:mileyja
ID: 20348181
i put the context of what I had in the program just after your last post. in the snippet
0
 

Author Comment

by:mileyja
ID: 20348183
we almost have it, Im dying here guys, come on....
0
 

Author Comment

by:mileyja
ID: 20348185
and you used IntPtr pnt = Marshal.AllocHGlobal(Marshal.SizeOf(p));

what is "p" , where did that come from?
0
 
LVL 55

Expert Comment

by:Jaime Olivares
ID: 20348192
I don't think your structure has valid data, you have to be sure about this before continuing with other problems
By example:
numchannels = 14829735428352901134
doesn't sound good to me.
0
 

Author Comment

by:mileyja
ID: 20348194
Your second method :

[DllImport("airpcap.dll", EntryPoint = "AirpcapTurnLedOff", CharSet = CharSet.Ansi)]
private extern static int AirpcapTurnLedOff([In, MarshalAs(UnmanagedType.LPStruct)]AirpcapHandle ah, uint lednum);
AirpcapTurnLedOff(handle, 0);

gave me:

Cannot marshal 'parameter #1': Invalid managed/unmanaged type combination (this value type must be paired with Struct).
0
 

Author Comment

by:mileyja
ID: 20348198
you were just too ambiguous, i just need the correct context for the first method you gave most likely!
0
 

Author Comment

by:mileyja
ID: 20348200
ok as for the structure, what would it have bad data??

Is there something wrong with the struct?
0
 

Author Comment

by:mileyja
ID: 20348220
With the below code I can get it to not throw an error but it does nothing and bool returns false meaning it failed.

any thoughts


        struct AirpcapHandle

        {

            public UInt32 OsHandle;

            public UInt32 ReadEvent;

            public UInt32 Flags;      // Currently unused

            public AIRPCAP_ADAPTER_TYPE AdapterType;

            public UInt32 hKey;

            public IntPtr pChannels;  //  AirpcapChannelInfo *

            public ulong NumChannels;

            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 512)]

            public string Ebuf;

        }
 

        [DllImport("airpcap.dll", EntryPoint = "AirpcapOpen", CharSet = CharSet.Ansi)]

        private extern static IntPtr AirpcapOpen(string DeviceName, StringBuilder Ebuf);
 

        [DllImport("airpcap.dll", EntryPoint = "AirpcapTurnLedOn", CharSet = CharSet.Ansi)]

        private extern static int AirpcapTurnLedOn(IntPtr ah, uint lednum);
 

        enum AIRPCAP_ADAPTER_TYPE : uint

        {

            ADAPTER_TYPE_AIRPCAP_DRIVER = 0,

            ADAPTER_TYPE_AR5416_DRIVER = 1

        }
 
 
 
 

        private unsafe void Form1_Load(object sender, EventArgs e)

        {

            string strFoundName = "";

            string strFoundDesc = "";
 

            AirpcapInterface.APCDevice[] devs;

            string outerror = "";

            AirpcapInterface.APCDevice dev;
 

            AirpcapInterface.AirpcapGetDeviceListWrap(out devs, ref outerror);
 

            foreach (AirpcapInterface.APCDevice i in devs)

            {

                strFoundName = i.name;

                strFoundDesc = i.description;
 

            }
 
 

            string pErrorBuffer = "";
 

         
 

           StringBuilder sb = new StringBuilder(512);  // size = AIRPCAP_ERRBUF_SIZE = 512

           IntPtr IP = new IntPtr();
 

         IP = AirpcapOpen(strFoundName, sb);

         AirpcapHandle AH = new AirpcapHandle();

         if (IP != IntPtr.Zero)   // prevent null pointer

         {

              AH = (AirpcapHandle)Marshal.PtrToStructure(IP, typeof(AirpcapHandle));

         }

         else

         {

             System.Windows.Forms.MessageBox.Show(sb.ToString());   // show error message

         }

         IntPtr pnt = Marshal.AllocHGlobal(Marshal.SizeOf(IP));

         Marshal.StructureToPtr(AH, pnt, false);

         int intWorked;

         intWorked = AirpcapTurnLedOn(IP, 1);

         Marshal.FreeHGlobal(pnt);

        }

Open in new window

0
 

Author Comment

by:mileyja
ID: 20348223
ok it works, with the whole lot, there were some mistakes in the dudes above code but the concept was there
0
 

Author Closing Comment

by:mileyja
ID: 31410887
had to do some tweaking but the concept were there for a guy who knows nothing about it.  Turns the leds on and off
0
 
LVL 55

Expert Comment

by:Jaime Olivares
ID: 20348233
try with this:

[StructLayout(LayoutKind.Sequential, Pack=4)]
struct AirpcapHandle
{
            public UInt32 OsHandle;
            public UInt32 ReadEvent;
            public UInt32 Flags;      // Currently unused
            public AIRPCAP_ADAPTER_TYPE AdapterType;
            public UInt32 hKey;
            public IntPtr pChannels;  //  AirpcapChannelInfo *
            public ulong NumChannels;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 512)]
            public string Ebuf;
}

and when invoking, test the value of NumChannels, I suspect it should be a small value.
0
 

Author Comment

by:mileyja
ID: 20348240
I think we are good man, I already gave you half points on the question.  It turns the led's on and off  There were just a few things that needed to happen.  

You successfully got me to the point where I had the ptr and converted to AH, turns out AH was good and i just needed to properly retransform it to a ptr before referencing it, who knew??

Well it works, it turns the led's on and off as it should in the functions, most of hte rest of the API i should be able to get, the hard part is done
0
 

Author Comment

by:mileyja
ID: 20354390
This in the end was the WORKING solution  thanks to all who put up with me.

  struct AirpcapHandle
        {
            public UInt32 OsHandle;
            public UInt32 ReadEvent;
            public UInt32 Flags;      // Currently unused
            public AIRPCAP_ADAPTER_TYPE AdapterType;
            public UInt32 hKey;
            public IntPtr pChannels;  //  AirpcapChannelInfo *
            public ulong NumChannels;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 512)]
            public string Ebuf;
        }

        [DllImport("airpcap.dll", EntryPoint = "AirpcapOpen", CharSet = CharSet.Ansi)]
        private extern static IntPtr AirpcapOpen(string DeviceName, StringBuilder Ebuf);

        [DllImport("airpcap.dll", EntryPoint = "AirpcapTurnLedOff", CharSet = CharSet.Ansi)]
        private extern static int AirpcapTurnLedOff(IntPtr ah, uint lednum);
        [DllImport("airpcap.dll", EntryPoint = "AirpcapTurnLedOn", CharSet = CharSet.Ansi)]
        private extern static int AirpcapTurnLedOn(IntPtr ah, uint lednum);

        enum AIRPCAP_ADAPTER_TYPE : uint
        {
            ADAPTER_TYPE_AIRPCAP_DRIVER = 0,
            ADAPTER_TYPE_AR5416_DRIVER = 1
        }




        private unsafe void Form1_Load(object sender, EventArgs e)
        {
            string strFoundName = "";
            string strFoundDesc = "";

            AirpcapInterface.APCDevice[] devs;
            string outerror = "";
            AirpcapInterface.APCDevice dev;

            AirpcapInterface.AirpcapGetDeviceListWrap(out devs, ref outerror);

            foreach (AirpcapInterface.APCDevice i in devs)
            {
                strFoundName = i.name;
                strFoundDesc = i.description;

            }


            string pErrorBuffer = "";

         

           StringBuilder sb = new StringBuilder(512);  // size = AIRPCAP_ERRBUF_SIZE = 512
           IntPtr IP = new IntPtr();

         IP = AirpcapOpen(strFoundName, sb);
         AirpcapHandle AH = new AirpcapHandle();
         if (IP != IntPtr.Zero)   // prevent null pointer
         {
              AH = (AirpcapHandle)Marshal.PtrToStructure(IP, typeof(AirpcapHandle));
         }
         else
         {
             System.Windows.Forms.MessageBox.Show(sb.ToString());   // show error message
         }
         IntPtr pnt = Marshal.AllocHGlobal(Marshal.SizeOf(IP));
         Marshal.StructureToPtr(AH, pnt, false);
         int intWorked;
         intWorked = AirpcapTurnLedOff(pnt, 0);
         intWorked = AirpcapTurnLedOn(pnt, 0);
     
         Marshal.FreeHGlobal(pnt);
        }
0

Featured Post

Top 6 Sources for Identifying Threat Actor TTPs

Understanding your enemy is essential. These six sources will help you identify the most popular threat actor tactics, techniques, and procedures (TTPs).

Join & Write a Comment

Introduction Hi all and welcome to my first article on Experts Exchange. A while ago, someone asked me if i could do some tutorials on object oriented programming. I decided to do them on C#. Now you may ask me, why's that? Well, one of the re…
For those of you who don't follow the news, or just happen to live under rocks, Microsoft Research released a beta SDK (http://www.microsoft.com/en-us/download/details.aspx?id=27876) for the Xbox 360 Kinect. If you don't know what a Kinect is (http:…
The goal of this video is to provide viewers with basic examples to understand recursion in the C programming language.
The goal of this video is to provide viewers with basic examples to understand and use conditional statements in the C programming language.

744 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

9 Experts available now in Live!

Get 1:1 Help Now