
// GameAssist.cpp : 定义应用程序的类行为。
//

#include "stdafx.h"
#include "GameAssist.h"
#include "GameAssistDlg.h"

// directx
#include <Dshow.h>
#include <strmif.h>
#pragma comment(lib, "strmiids.lib")
#define VI_MAX_CAMERAS 20
// DEFINE_GUID(CLSID_SystemDeviceEnum, 0x62be5d10, 0x60eb, 0x11d0, 0xbd, 0x3b, 0x00, 0xa0, 0xc9, 0x11, 0xce, 0x86);
// DEFINE_GUID(CLSID_VideoInputDeviceCategory, 0x860bb310, 0x5d01, 0x11d0, 0xbd, 0x3b, 0x00, 0xa0, 0xc9, 0x11, 0xce, 0x86);
// DEFINE_GUID(IID_ICreateDevEnum, 0x29840822, 0x5b84, 0x11d0, 0xbd, 0x3b, 0x00, 0xa0, 0xc9, 0x11, 0xce, 0x86);

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

//列出硬件设备
int listDevices(std::vector<std::string>& list)
{
	// 初始化COM环境;
	::CoInitialize(NULL);
	ICreateDevEnum *pDevEnum = NULL;
	IEnumMoniker *pEnum = NULL;
	int deviceCounter = 0;	

	//HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum,NULL,CLSCTX_INPROC_SERVER,IID_ICreateDevEnum,reinterpret_cast<void**>(&pDevEnum));
	HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum,NULL,CLSCTX_INPROC_SERVER,IID_ICreateDevEnum,(void**)(&pDevEnum));
	if (SUCCEEDED(hr))
	{
		hr = pDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory,&pEnum, 0);
		if (hr == S_OK){

			IMoniker *pMoniker = NULL;
			while (pEnum->Next(1, &pMoniker, NULL) == S_OK)
			{
				IPropertyBag *pPropBag;
				hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag,(void**)(&pPropBag));

				if (FAILED(hr)) {
					pMoniker->Release();
					continue; // Skip this one, maybe the next one will work.
				}

				VARIANT varName;
				VariantInit(&varName);
				hr = pPropBag->Read(L"Description", &varName, 0);
				if (FAILED(hr))
				{
					hr = pPropBag->Read(L"FriendlyName", &varName, 0);
				}

				if (SUCCEEDED(hr))
				{
					hr = pPropBag->Read(L"FriendlyName", &varName, 0);
					int count = 0;
					char tmp[255] = { 0 };
					while (varName.bstrVal[count] != 0x00 && count < 255)
					{
						tmp[count] = (char)varName.bstrVal[count];
						count++;
					}
					list.push_back(tmp);
				}

				pPropBag->Release();
				pPropBag = NULL;
				pMoniker->Release();
				pMoniker = NULL;

				deviceCounter++;
			}

			pDevEnum->Release();
			pDevEnum = NULL;
			pEnum->Release();
			pEnum = NULL;
		}
	}

	// 释放COM环境;
	::CoUninitialize();

	return deviceCounter;
}

#define OUTPUT_PIN       1
#define OUTPUT_MEDIATYPE 1

char* GuidToString(const GUID &guid)
{
	int buf_len=64;
	char *buf =(char *)malloc(buf_len);
	_stprintf_s(
		buf,
		buf_len,
		"{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
		guid.Data1, guid.Data2, guid.Data3,
		guid.Data4[0], guid.Data4[1],
		guid.Data4[2], guid.Data4[3],
		guid.Data4[4], guid.Data4[5],
		guid.Data4[6], guid.Data4[7]);
	//printf("%s\n",buf);
	return buf;
}

int DirectShowDemo()
{
	// Init COM
	HRESULT hr=NULL;
	hr= CoInitialize(NULL);
	if (FAILED(hr)){
		printf("Error, Can not init COM.");
		return -1;
	}
	printf("===============Directshow Filters ===============\n");
	ICreateDevEnum *pSysDevEnum = NULL;
	hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void **)&pSysDevEnum);
	if (FAILED(hr)){
		return hr;
	}
 
	IEnumMoniker *pEnumCat = NULL;
	//Category	
	/************************************************************************
	Friendly Name	                      CLSID
	-------------------------------------------------------------------------
	Audio Capture Sources	              CLSID_AudioInputDeviceCategory
	Audio Compressors	                  CLSID_AudioCompressorCategory
	Audio Renderers	                      CLSID_AudioRendererCategory
	Device Control Filters	              CLSID_DeviceControlCategory
	DirectShow Filters	                  CLSID_LegacyAmFilterCategory
	External Renderers	                  CLSID_TransmitCategory
	Midi Renderers	                      CLSID_MidiRendererCategory
	Video Capture Sources	              CLSID_VideoInputDeviceCategory
	Video Compressors	                  CLSID_VideoCompressorCategory
	WDM Stream Decompression Devices	  CLSID_DVDHWDecodersCategory
	WDM Streaming Capture Devices	      AM_KSCATEGORY_CAPTURE
	WDM Streaming Crossbar Devices	      AM_KSCATEGORY_CROSSBAR
	WDM Streaming Rendering Devices	      AM_KSCATEGORY_RENDER
	WDM Streaming Tee/Splitter Devices	  AM_KSCATEGORY_SPLITTER
	WDM Streaming TV Audio Devices	      AM_KSCATEGORY_TVAUDIO
	WDM Streaming TV Tuner Devices	      AM_KSCATEGORY_TVTUNER
	WDM Streaming VBI Codecs	          AM_KSCATEGORY_VBICODEC 
	************************************************************************/
	hr = pSysDevEnum->CreateClassEnumerator(CLSID_VideoCompressorCategory, &pEnumCat, 0);
	//hr = pSysDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEnumCat, 0);
	//hr = pSysDevEnum->CreateClassEnumerator(CLSID_AudioCompressorCategory, &pEnumCat, 0);
	//hr = pSysDevEnum->CreateClassEnumerator(CLSID_AudioInputDeviceCategory, &pEnumCat, 0);
	//hr = pSysDevEnum->CreateClassEnumerator(CLSID_MediaMultiplexerCategory, &pEnumCat, 0);
	//hr = pSysDevEnum->CreateClassEnumerator(CLSID_LegacyAmFilterCategory, &pEnumCat, 0);
 
	if (hr != S_OK) {
		pSysDevEnum->Release();
		return -1;
	}
	
	IMoniker *pMoniker = NULL;
	ULONG monikerFetched;
	//Filter
	while(pEnumCat->Next(1, &pMoniker, &monikerFetched) == S_OK){
		IPropertyBag *pPropBag;
		VARIANT varName;
		IBaseFilter *pFilter;
		hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag,(void **)&pPropBag);
		if (FAILED(hr)){
			pMoniker->Release();
			continue;
		}
		VariantInit(&varName);
		hr = pPropBag->Read(L"FriendlyName", &varName, 0);
		//"FriendlyName": The name of the device.
		//"Description": A description of the device.
		//Filter Info================
		_tprintf_s(_T("[%ls]\n"),varName.bstrVal);
		VariantClear(&varName);
		//========================
#if OUTPUT_PIN
		hr = pMoniker->BindToObject(NULL, NULL, IID_IBaseFilter,(void**)&pFilter);
		if (!pFilter){
			continue;
		}
 
		IEnumPins * pinEnum = NULL;
		IPin * pin = NULL;
		ULONG pinFetched = 0;
		if (FAILED(pFilter->EnumPins(&pinEnum))){
			pinEnum->Release();
			continue;	
		}
		pinEnum->Reset();
		//Pin Info
		while (SUCCEEDED(pinEnum->Next(1, &pin, &pinFetched)) && pinFetched){
			if (!pin){
				continue;
			}
			PIN_INFO pinInfo;
			if (FAILED(pin->QueryPinInfo(&pinInfo))){
				continue;
			}
			printf("\t[Pin] ");
				switch(pinInfo.dir){
				case PINDIR_INPUT:printf("Dir:Input  \t");break;
				case PINDIR_OUTPUT:printf("Dir:Output \t");break;
				default:printf("Dir:Unknown\n");break;
			}
			_tprintf_s(_T("Name:%ls\n"),pinInfo.achName);
					
			//MediaType
#if OUTPUT_MEDIATYPE
			IEnumMediaTypes *mtEnum=NULL;
			AM_MEDIA_TYPE   *mt=NULL;
			if( FAILED( pin->EnumMediaTypes( &mtEnum )) )
				break;
			mtEnum->Reset();
			
			ULONG mtFetched = 0;
 
			while (SUCCEEDED(mtEnum->Next(1, &mt, &mtFetched)) && mtFetched){
 
				printf("\t\t[MediaType]\n");
				//Video
				char *MEDIATYPE_Video_str=GuidToString(MEDIATYPE_Video);
				//Audio
				char *MEDIATYPE_Audio_str=GuidToString(MEDIATYPE_Audio);
				//Stream
				char *MEDIATYPE_Stream_str=GuidToString(MEDIATYPE_Stream);
				//Majortype
				char *majortype_str=GuidToString(mt->majortype);
				//Subtype
				char *subtype_str=GuidToString(mt->subtype);
 
				printf("\t\t  Majortype:");
				if(strcmp(majortype_str,MEDIATYPE_Video_str)==0){
					printf("Video\n");
				}else if(strcmp(majortype_str,MEDIATYPE_Audio_str)==0){
					printf("Audio\n");
				}else if(strcmp(majortype_str,MEDIATYPE_Stream_str)==0){
					printf("Stream\n");
				}else{
					printf("Other\n");
				}
				printf("\t\t  Subtype GUID:%s",subtype_str);
 
				free(MEDIATYPE_Video_str);
				free(MEDIATYPE_Audio_str);
				free(MEDIATYPE_Stream_str);
				free(subtype_str);
				free(majortype_str);
				printf("\n");
 
			}
#endif
			pin->Release();
				
		}
		pinEnum->Release();
 
		pFilter->Release();
#endif
		
		pPropBag->Release();
		pMoniker->Release();
	}
	pEnumCat->Release();
	pSysDevEnum->Release();
	printf("=================================================\n");
	CoUninitialize();
	return 0;

}

// CGameAssistApp

BEGIN_MESSAGE_MAP(CGameAssistApp, CWinAppEx)
	ON_COMMAND(ID_HELP, &CWinApp::OnHelp)
END_MESSAGE_MAP()


// CGameAssistApp 构造

CGameAssistApp::CGameAssistApp()
{
	// TODO: 在此处添加构造代码，
	// 将所有重要的初始化放置在 InitInstance 中
}


// 唯一的一个 CGameAssistApp 对象

CGameAssistApp theApp;


// CGameAssistApp 初始化

BOOL CGameAssistApp::InitInstance()
{
	// 如果一个运行在 Windows XP 上的应用程序清单指定要
	// 使用 ComCtl32.dll 版本 6 或更高版本来启用可视化方式，
	//则需要 InitCommonControlsEx()。否则，将无法创建窗口。
	INITCOMMONCONTROLSEX InitCtrls;
	InitCtrls.dwSize = sizeof(InitCtrls);
	// 将它设置为包括所有要在应用程序中使用的
	// 公共控件类。
	InitCtrls.dwICC = ICC_WIN95_CLASSES;
	InitCommonControlsEx(&InitCtrls);

	CWinAppEx::InitInstance();

	AfxEnableControlContainer();

#if 0
	DirectShowDemo();
	std::vector<std::string> vtDevices;
	listDevices(vtDevices);
	// 枚举USB摄像头设备;
	ICreateDevEnum *pCreateDevEnum=0;
	HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void**)&pCreateDevEnum);
#endif

	

	// 标准初始化
	// 如果未使用这些功能并希望减小
	// 最终可执行文件的大小，则应移除下列
	// 不需要的特定初始化例程
	// 更改用于存储设置的注册表项
	// TODO: 应适当修改该字符串，
	// 例如修改为公司或组织名
	SetRegistryKey(_T("应用程序向导生成的本地应用程序"));

	CGameAssistDlg dlg;
	m_pMainWnd = &dlg;
	INT_PTR nResponse = dlg.DoModal();
	if (nResponse == IDOK)
	{
		// TODO: 在此放置处理何时用
		//  “确定”来关闭对话框的代码
	}
	else if (nResponse == IDCANCEL)
	{
		// TODO: 在此放置处理何时用
		//  “取消”来关闭对话框的代码
	}

	// 由于对话框已关闭，所以将返回 FALSE 以便退出应用程序，
	//  而不是启动应用程序的消息泵。
	return FALSE;
}
