1. 程式人生 > >MFC學習筆記 — 看小白如何實現音樂播放器(USB-HID 音效卡 wav播放)

MFC學習筆記 — 看小白如何實現音樂播放器(USB-HID 音效卡 wav播放)

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

XX  作       者:ZHS(文化人)

XX  聯絡方式:文章末尾Chat快問(或進群:471144274

XX  要說的話:作者水平有限,難免有不足之處,懇請指正!

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

1、USB裝置的列舉和讀寫:

我把程式碼中PVN改為了usagepage,因為PVN會有多個裝置,而usagepage可以確保只有一個;

獲得usagepage需要新增如下程式碼:

hDevHandle=CreateFile(MyDevPathName, 
			NULL, 
			FILE_SHARE_READ|FILE_SHARE_WRITE, 
			NULL,OPEN_EXISTING,
			FILE_ATTRIBUTE_NORMAL,
			NULL);
						
//獲取裝置的屬性並儲存在DevAttributes結構體中
Result=HidD_GetAttributes(hDevHandle, &DevAttributes);
//關閉剛剛開啟的裝置
CloseHandle(hDevHandle);
//如果獲取成功,則將屬性中的VID、PID以及裝置版本號與我們需要的
//進行比較,如果都一致的話,則說明它就是我們要找的裝置。
if(MyVid == DevAttributes.VendorID)
{
	if(MyPid == DevAttributes.ProductID)
	{
		//這裡進行讀寫訪問開啟裝置
		
		if(!HidD_GetPreparsedData(hWriteHandle, &PreparsedData))
		{
			CloseHandle(hWriteHandle);
			return FALSE;
		}
		if(!HidP_GetCaps(PreparsedData, &Capabilities))
		{
			CloseHandle(hWriteHandle);
			return FALSE;
		}
		if(Capabilities.UsagePage == 0xffa0)
		{
			MyDevFound = TRUE;
		}
	}
}

如果以上的連結中,寫資料失敗的話,建議改用下面的寫介面:

BOOL CUsbDlg::OnBUTTONSend(UCHAR send_buf[64]) 
{
	CString DevicePath;
	BOOL Result;
	UINT LastError;

	unsigned long numBytesReturned;
	DevicePath=temp;
	HANDLE hCom = CreateFile (
		DevicePath,
		GENERIC_READ | GENERIC_WRITE,
		FILE_SHARE_READ | FILE_SHARE_WRITE,
		NULL,
		OPEN_EXISTING, 0,
		NULL);
	if (hCom == INVALID_HANDLE_VALUE)
	{}
	DataInSending=TRUE;
	Result = WriteFile(hCom, send_buf, 19, &numBytesReturned, NULL);
	//如果函式返回失敗,則可能是真的失敗,也可能是IO掛起了
	if(Result==FALSE)
	{
		//獲取最後錯誤程式碼
		LastError=GetLastError();
		//看是否是真的IO掛起
		if((LastError==ERROR_IO_PENDING)||(LastError==ERROR_SUCCESS))
		{
			return TRUE;
		}
		//否則,是函式呼叫時發生錯誤,顯示錯誤程式碼
		else
		{
			DataInSending=FALSE;
			AddToInfOut("傳送失敗,錯誤程式碼:"+itos(LastError));
			//如果最後錯誤為1,說明該裝置不支援該函式。
			if(LastError==1)
			{
				AddToInfOut("該裝置不支援WriteFile函式。", FALSE);
			}
			return FALSE;
		}
	}
	//否則,函式返回成功
	else
	{
		DataInSending=FALSE;
		return TRUE;
	}
	return TRUE;
}

作者的程式碼是排除了預設音效卡,選擇新的音效卡,但若是有兩個新的音效卡呢?

我去掉了判斷預設音訊裝置的程式碼,把紅色框內的程式碼修改為如下:

setlocale(LC_ALL,"");//此句必須要加上
char mbBuffer[256] = {0};
size_t  count;
count = wcstombs(mbBuffer, friendlyName.pwszVal, 256);// 轉換並返回多位元組字串的長度
if(strstr(mbBuffer, "Usb Dongle"))
	SetDefaultAudioPlaybackDevice(wstrID);

3、播放音樂:

新增如下程式碼,介面上加一個編輯框,實現動態選擇wav檔案:

char buf[256];
sprintf(buf, _T("open %s.wav alias wave"), get_wav_filename_from_edit);
mciSendString(buf, NULL, 0, NULL);//alias後面為裝置名稱
mciSendString(_T("play wave wait"), NULL, 0, NULL);//wait表示播放完畢之後才返回,最好加上去
mciSendString(_T("close wave"), NULL, 0, NULL);

注意:只有使用生成的.exe才能播放音樂,VS裡除錯時是播放不成功的;

4、編譯可能會遇到一些錯誤,其中一類錯誤的原因:

5、HID使用的庫檔案在這裡,用到的標頭檔案如下,:

extern "C" {
#include "hidsdi.h"
#include "setupapi.h"
}
#include <afxwin.h>
#include "Common.h"
#include <wchar.h>
#include <locale.h>
#include "Mmdeviceapi.h"
#include "PolicyConfig.h"
#include "Propidl.h"
#include "Functiondiscoverykeys_devpkey.h"