📄 cudaldongle.cpp
字号:
#include <Cudal.h>
#include "UsbIoPipe.h"
// Initialize the shared enumeration mutex
HANDLE CudalDongle::m_hMutexEnum = 0;
/// Default GUID (used when passing *pGuid = NULL to EnumDongles and CreateDongle)
/// { 0x92b5d269, 0xf794, 0x49d9, {0x8d, 0x29, 0xcc, 0x3d, 0xee, 0x8b, 0xa, 0x1} }
static const GUID DEFAULT_GUID = { 0x92b5d269, 0xf794, 0x49d9, {0x8d, 0x29, 0xcc, 0x3d, 0xee, 0x8b, 0xa, 0x1} };
/** \brief Protected constructor (to prevent user instantiation)
*
* The constructor initializes the CudalDongle object by storing the parameters, and creates a named
* mutex from the manufacturer, product and serial number string descriptors. If it finds that the mutex
* already exists, the \ref m_dongleUsed parameter will be set, and \ref CudalDongle::CreateDongle() will
* immediately destroy it.
*
* \note The constructor should only be called by \ref CudalDongle::CreateDongle().
*
* \param[in] *pDongleInfo
* The same CUDAL_DONGLE_INFO pointer that was passed to \ref CudalDongle::CreateDongle()
* \param[in] *pUsbIo
* The USBIO object created by \ref CudalDongle::CreateDongle()
*/
CudalDongle::CudalDongle(CUDAL_DONGLE_INFO *pDongleInfo, CUsbIo *pUsbIo) {
// Store the constructor parameters
memcpy(&m_dongleInfo, pDongleInfo, sizeof(CUDAL_DONGLE_INFO));
m_pUsbIo = pUsbIo;
// Create the mutex name, which uniquely identifies each physical dongle
char pMutexName[MAX_PATH * 4];
sprintf(pMutexName, "CUDAL_MUTEX_DONGLE SN=%s,P=%s,M=%s", pDongleInfo->pSerialNumber, pDongleInfo->pManufacturer, pDongleInfo->pProduct);
// Limit the number of characters in the name to MAX_PATH (CreateMutex() limitation)
pMutexName[MAX_PATH - 1] = '\0';
// Check whether any other CebalDongle object in any process is linked to the same physical dongle
m_hMutexDongle = CreateMutex(NULL, TRUE, pMutexName);
m_dongleUsed = (m_hMutexDongle == NULL) || (GetLastError() == ERROR_ALREADY_EXISTS);
} // CudalDongle
/** \brief Destroys the dongle object, and makes the dongle hardware available for other applications
*
* Delete all associated \ref CudalPipe objects before destroying the dongle.
*
* \note The destructor must be called in order to release system resources and make the dongle hardware
* available for other applications. If this is not done properly, the dongle hardware will be
* unavailable until the process that created the \ref CudalDongle object has been terminated.
*
* \sa CudalDongle::CreateDongle
*/
/*virtual*/ CudalDongle::~CudalDongle() {
if (m_pUsbIo) delete m_pUsbIo;
if (m_hMutexDongle) CloseHandle(m_hMutexDongle);
} // ~CudalDongle
/** \brief Enters data into the supplied CUDAL_DONGLE_INFO struct
*
* This function is used during enumeration and when creating dongle and pipe objects.
*
* \param[out] *pDongleInfo
* The CUDAL_DONGLE_INFO structure to be filled in
* \param[in] *pUsbIo
* A pointer to the USBIO object to gather the information from
*
* \return
* \c TRUE if successful, otherwise \c FALSE, indicating a USB communication error
*
* \sa CudalDongle::EnumDongles, CudalDongle::CreateDongle, CudalDongle::CreatePipe
*/
/*static*/ BOOL CudalDongle::CreateDongleInfo(CUDAL_DONGLE_INFO *pDongleInfo, CUsbIo *pUsbIo) {
BYTE pBuffer[256];
DWORD length;
int result;
// 1. Get the ID and version numbers from the device descriptor
USB_DEVICE_DESCRIPTOR deviceDesc;
result = pUsbIo->GetDeviceDescriptor(&deviceDesc);
pDongleInfo->vendorId = deviceDesc.idVendor;
pDongleInfo->productId = deviceDesc.idProduct;
pDongleInfo->productVersion = deviceDesc.bcdDevice;
// 2. Get the manufacturer name
USB_STRING_DESCRIPTOR *pStringDesc = (USB_STRING_DESCRIPTOR*) pBuffer;
result |= pUsbIo->GetStringDescriptor(pStringDesc, length = 256, deviceDesc.iManufacturer);
length = WideCharToMultiByte(CP_ACP, 0, pStringDesc->bString, (pStringDesc->bLength - 2) / 2, pDongleInfo->pManufacturer, 128, NULL, NULL);
pDongleInfo->pManufacturer[length] = '\0';
// 3. Get the product name
result |= pUsbIo->GetStringDescriptor(pStringDesc, length = 256, deviceDesc.iProduct);
length = WideCharToMultiByte(CP_ACP, 0, pStringDesc->bString, (pStringDesc->bLength - 2) / 2, pDongleInfo->pProduct, 128, NULL, NULL);
pDongleInfo->pProduct[length] = '\0';
// 4. Get the serial number
result |= pUsbIo->GetStringDescriptor(pStringDesc, length = 256, deviceDesc.iSerialNumber);
length = WideCharToMultiByte(CP_ACP, 0, pStringDesc->bString, (pStringDesc->bLength - 2) / 2, pDongleInfo->pSerialNumber, 128, NULL, NULL);
pDongleInfo->pSerialNumber[length] = '\0';
return (result == USBIO_ERR_SUCCESS);
} // CreateDongleInfo
/** \brief Enumerates available USB dongles
*
* This function populates a table of \ref CUDAL_DONGLE_INFO structures, which contain ID information
* about the USB dongles currently connected to the computer. One of these structures is then passed on
* to \ref CudalDongle::CreateDongle() in order to create a \ref CudalDongle object.
*
* \note The information contained in the \ref CUDAL_DONGLE_INFO structure should uniquely identify each
* physical USB dongle. The device must provide manufacturer, product and serial number string
* descriptors, which, put together, must form a unique text string. If two dongles have identical
* string descriptors, the CUDAL library will only be able to access one of them (first found).
*
* \param[out] *pDongleInfo
* Pointer to a caller-provided table of \ref CUDAL_DONGLE_INFO structures
* \param[in] maxCount
* Number of entries in the \ref CUDAL_DONGLE_INFO table, \c *pDongleInfo
* \param[in] *pGuid
* A pointer to the \c GUID that matches the VID/PID for the desired device(s). If this parameter
* is \c NULL, a default GUID will be used.
*
* \return
* The number of valid entries in \c *pDongleInfo
*
* \sa CudalDongle::CreateDongle
*/
/*static*/ int CudalDongle::EnumDongles(CUDAL_DONGLE_INFO *pDongleInfo, int maxCount, const GUID *pGuid) {
HDEVINFO hDevInfo;
CUsbIo usbIo;
int count = 0;
int result;
// Use the default GUID if none was specified
if (!pGuid) pGuid = &DEFAULT_GUID;
// Start by wiping out the dongle info table
memset(pDongleInfo, 0x00, sizeof(CUDAL_DONGLE_INFO) * maxCount);
// Open/create the mutex used to make EnumDongles() and CreateDongle() safe (EnumDongles() is always
// called first, so it's safe to do it here only)
if (!m_hMutexEnum) {
m_hMutexEnum = CreateMutex(NULL, FALSE, "CUDAL_MUTEX_ENUM");
if (!m_hMutexEnum) return 0;
}
// Enter the critical section
result = WaitForSingleObject(m_hMutexEnum, 500);
if (result == WAIT_OBJECT_0 || result == WAIT_ABANDONED) {
// Create a list of attached dongles
if (hDevInfo = CUsbIo::CreateDeviceList(pGuid)) {
// Traverse through the list and gather information about each
for (int n = 0; n < maxCount; n++) {
if (usbIo.Open(n, hDevInfo, pGuid) == USBIO_ERR_SUCCESS) {
if (CreateDongleInfo(&pDongleInfo[count], &usbIo)) count++;
usbIo.Close();
}
}
// Delete the dongle list
CUsbIo::DestroyDeviceList(hDevInfo);
}
// Release the enumeration mutex
ReleaseMutex(m_hMutexEnum);
}
// Return the number of valid CUDAL_DONGLE_INFO entries
return count;
} // EnumDongles
/** \brief Creates a dongle object
*
* This function creates a \ref CudalDongle object based on one of the \ref CUDAL_DONGLE_INFO structures
* provided by the \ref CudalDongle::EnumDongles() function. The object is returned by pointer, which
* \b must be deleted when the object is no longer to be used.
*
* \note There can only be one \ref CudalDongle object for each physical USB dongle. This is ensured by
* creating a named mutex, based on the information found in the \ref CUDAL_DONGLE_INFO structure. If the
* mutex cannot be created, the dongle is already in use, and \ref CudalDongle::CreateDongle() will
* abort, and return \c NULL.
*
* \param[out] *pDongleInfo
* A pointer to the \ref CUDAL_DONGLE_INFO structure representing the physical dongle
* \param[in] configurationIndex
* A zero-based index for the device configuration to be set. If a value of -1 is used, the set
* configuration request will not be sent.
* \param[in] *pGuid
* The same \c GUID that was passed to \ref CudalDongle::EnumDongles()
*
* \return
* A pointer to the created \ref CudalDongle object, or \c NULL if the operation failed (e.g. the
* device was removed after enumeration, or is already in use)
*
* \sa CudalDongle::EnumDongles, CudalDongle::~CudalDongle, CudalDongle::CreatePipe
*/
/*static*/ CudalDongle* CudalDongle::CreateDongle(CUDAL_DONGLE_INFO *pDongleInfo, BYTE configurationIndex, const GUID *pGuid) {
CudalDongle *pDongle = NULL;
CUDAL_DONGLE_INFO currentInfo;
HDEVINFO hDevInfo;
CUsbIo *pUsbIo = new CUsbIo();
int result;
// Use the default GUID if none was specified
if (!pGuid) pGuid = &DEFAULT_GUID;
// Enter the critical section
result = WaitForSingleObject(m_hMutexEnum, 500);
if (result == WAIT_OBJECT_0 || result == WAIT_ABANDONED) {
// Create a list of attached dongles
if (hDevInfo = CUsbIo::CreateDeviceList(pGuid)) {
// Traverse through the list and try to find a match
int n = 0;
// If the device could be opened...
while (pUsbIo->Open(n++, hDevInfo, pGuid) == USBIO_ERR_SUCCESS) {
// Compare the dongle information
memset(¤tInfo, 0x00, sizeof(CUDAL_DONGLE_INFO));
if (CreateDongleInfo(¤tInfo, pUsbIo)) {
// Create the dongle object when we have a match, and then break out of the loop
if (memcmp(¤tInfo, pDongleInfo, sizeof(CUDAL_DONGLE_INFO)) == 0) {
pDongle = new CudalDongle(pDongleInfo, pUsbIo);
pDongle->m_pUsbIo = pUsbIo;
pDongle->m_pGuid = pGuid;
break;
}
}
pUsbIo->Close();
}
// Delete the dongle list
CUsbIo::DestroyDeviceList(hDevInfo);
}
// Release the enumeration mutex
ReleaseMutex(m_hMutexEnum);
}
// Clean up if no dongle object was created
if (!pDongle) delete pUsbIo;
// Don't return anything if the dongle is already in use
if (pDongle && pDongle->IsDongleUsed()) {
delete pDongle;
pDongle = NULL;
}
// Configure the device
if (pDongle && (configurationIndex != (BYTE) -1)) pDongle->SetConfiguration(configurationIndex);
return pDongle;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -